Skip to content

Class: DomainPipeline

run()의 반환값 타입. 성공한 리소스의 DomainState 맵에 선택적으로 _errors 배열이 포함된다.

Constructors

Constructor

ts
new DomainPipeline(resourceMap, options?): DomainPipeline;

DomainPipeline 인스턴스를 생성한다.

직접 호출 금지. DomainState.all(resourceMap, options)을 사용한다. DomainState.all()은 내부적으로 DomainState.PipelineConstructor를 통해 이 생성자를 호출한다.

Parameters

resourceMap

ResourceMap

키: 리소스 식별자, 값: Promise<DomainState>

options?

PipelineOptions = {}

파이프라인 실행 옵션

Returns

DomainPipeline

Example

ts
// ❌ 직접 생성 금지
// new DomainPipeline({ ... });

// ✅ DomainState.all()을 통해 사용
const result = await DomainState.all({ roles: api.get('/api/roles') }, { strict: false })
    .after('roles', async roles => { ... })
    .run();

Properties

_failurePolicy

ts
_failurePolicy: "ignore" | "rollback-all" | "fail-fast";

파이프라인 실패 시 보상 트랜잭션 정책. 'ignore'(기본값)이면 기존 동작과 동일하다.


_queue

ts
_queue: QueueEntry[];

after() 핸들러 큐. 등록 순서가 곧 실행 순서다. run() 2단계에서 이 배열을 순서대로 순차 await한다.


_resourceMap

ts
_resourceMap: ResourceMap;

병렬 fetch 대상 리소스 맵. 키: 리소스 식별자, 값: Promise<DomainState>. run() 실행 시 Promise.allSettled()에 전달된다.


_strict

ts
_strict: boolean;

strict 모드 플래그. true이면 첫 실패에서 즉시 reject, false이면 _errors에 기록 후 계속.

Methods

_compensate()

ts
_compensate(resolved, keys): void;

지정된 키 목록의 DomainState에 순서대로 restore()를 호출한다.

fail-fast 정책에서는 완료 키를 **역순(LIFO)**으로 전달하고, rollback-all 정책에서는 resolved의 전체 키를 전달한다. restore()는 멱등성이 보장되므로 스냅샷이 없는 인스턴스에 호출해도 안전하다.

Parameters

resolved

Record<string, DomainState>

1단계 fetch에서 성공한 DomainState 맵

keys

string[]

restore()를 호출할 키 목록. 배열 순서가 실행 순서가 된다.

Returns

void


_dispatchPipelineRollback()

ts
_dispatchPipelineRollback(errors, resolved): void;

파이프라인 보상 트랜잭션 완료 후 dsm:pipeline-rollback CustomEvent를 발행한다.

소비자 앱이 이 이벤트를 구독하여 어느 리소스가 실패했는지 파악하고 서버 롤백 API 호출 또는 UI 에러 모달 표시를 직접 구현할 수 있다. Node.js / Vitest 환경에서는 window가 없으므로 건너뛴다.

Parameters

errors

PipelineError[]

실패한 에러 목록

resolved

Record<string, DomainState>

성공한 DomainState 맵

Returns

void


after()

ts
after(key, handler): DomainPipeline;

특정 리소스에 대한 후처리 핸들러를 큐에 등록한다.

등록 순서가 run() 에서의 실행 순서가 된다. run()이 호출될 때까지 핸들러는 실행되지 않는다.

fetch가 성공한 리소스만 핸들러가 실행된다. fetch가 실패한 리소스의 핸들러는 run() 2단계에서 자동으로 건너뛰며 _errors에 스킵 이유가 기록된다.

Parameters

key

string

resourceMap의 키 이름. 존재하지 않는 키면 즉시 Error throw.

handler

AfterHandler

해당 DomainState를 인자로 받는 핸들러 함수. async 함수 또는 일반 함수 모두 지원.

Returns

DomainPipeline

체이닝을 위한 this 반환

Throws

keyresourceMap에 없는 경우

Throws

handler가 함수가 아닌 경우

Examples

ts
DomainState.all({
    roles: api.get('/api/roles'),
    user:  api.get('/api/users/1'),
})
.after('roles', async roles => {
    roles.renderTo('#roleDiv', { type: 'select', valueField: 'roleId', labelField: 'roleName' });
})
.after('user', async user => {
    user.bindForm('#userForm');
})
.run();
ts
pipeline.after('nonExistent', handler);
// → Error: [DSM] Pipeline: 'nonExistent' 키가 resourceMap에 없습니다.

run()

ts
run(): Promise<PipelineResult>;

등록된 fetch Promise와 after() 핸들러를 순서대로 실행한다.

실행 흐름

1단계 — 병렬 fetch

Promise.allSettled()로 모든 리소스를 병렬로 fetch한다. allSettled를 사용하므로 일부 실패가 나머지 fetch를 중단시키지 않는다.

  • 성공(fulfilled): resolved[key]DomainState 저장
  • 실패(rejected):
    • strict: falseerrors{ key, error: reason } 기록 후 계속
    • strict: truereason을 즉시 throw
    • 디버그 채널에 broadcastError(key, reason) 전송

2단계 — after() 핸들러 순차 실행

_queue를 등록 순서대로 순회하며 각 핸들러를 await한다.

  • fetch 실패로 resolved[key]가 없는 경우: 스킵 이유를 errors에 기록하고 continue
  • 핸들러 성공: 정상 진행
  • 핸들러 실패:
    • strict: falseerrors에 기록 후 다음 핸들러 계속
    • strict: true → 즉시 throw
    • 디버그 채널에 broadcastError(key, err) 전송

3단계 — 보상 트랜잭션 (failurePolicy에 따라)

  • 'rollback-all': 모든 핸들러 완료 후 에러가 하나라도 있으면 전체 resolvedrestore()를 호출한다.
  • 'fail-fast': 첫 번째 핸들러 실패 시 즉시 중단하고 이전 성공 상태들에 **역순(LIFO)**으로 restore()를 호출한다.
  • 'ignore': 보상 없음. 기존 동작과 동일.

4단계 — 결과 반환

errors가 있으면 output._errors에 포함하여 반환한다.

Returns

Promise<PipelineResult>

성공한 리소스의 DomainState 맵. 실패 항목이 있으면 _errors 포함.

Throws

strict: true이고 fetch 또는 핸들러가 실패한 경우 에러를 즉시 throw

Examples

ts
const result = await DomainState.all({
    roles: api.get('/api/roles'),
    user:  api.get('/api/users/INVALID'), // 404 예상
}, { strict: false })
.after('roles', async roles => { roles.renderTo('#roleDiv', { ... }); })
.run();

// result.roles  → DomainState (성공)
// result.user   → undefined (fetch 실패)
// result._errors → [{ key: 'user', error: { status: 404, ... } }]
result._errors?.forEach(({ key, error }) => console.warn(key, error));
ts
try {
    const result = await DomainState.all({ ... }, { strict: true })
        .after('roles', async roles => { ... })
        .run();
} catch (err) {
    console.error('Pipeline 중단:', err);
}
ts
const { roles, user } = await DomainState.all({ roles: ..., user: ... }).run();
user.data.name = 'Davi';
await user.save('/api/users/1');

Released under the ISC License.