Durable Execution
크래시·재시작·페일오버를 넘어서 중단 지점부터 재개되는 실행 모델
핵심 개념
Durable execution은 워크플로의 각 단계를 체크포인트하고 결정적 재생(deterministic replay)으로 복구해, 프로세스가 죽어도 처음부터가 아니라 마지막 체크포인트부터 이어가는 실행 모델이다. Temporal, Azure Durable Functions, 그리고 최근의 pg_durable이 이 계열이다.
핵심은 두 가지 분리다.
- 워크플로 상태를 프로세스 메모리가 아닌 durable 스토어에 둔다
- 한 단계의 실패가 전체 재실행을 요구하지 않게 단계 경계를 명시적으로 만든다
왜 필요한가 — 두 가지 워크어라운드
Postgres 팀이 백그라운드 작업(변환, 야간 롤업, 임베딩 생성, 승인 대기)이 필요해질 때 거치는 전형적 경로:
1) 전부 하나의 함수에 우겨넣기
- 커넥션 하나가 내내 묶임
- 전부 하나의 거대 트랜잭션 → 긴 락, 부분 진행 가시성 없음
- 연결이 끊기거나 DB가 재시작하면 실행 전체가 소실
- step별 재시도·병렬·스케줄·human-in-the-loop 일시정지가 없음
2) 밖으로 빼기
- 잡 큐, 폴링 워커, 상태 테이블, step 조율, 재시도 로직, 크래시 복구 sweep, 정리 잡
- 비즈니스 로직을 건드리기도 전에 분산 시스템을 새로 짓고 운영하게 된다
둘 다 같은 빠진 프리미티브에 대한 워크어라운드다: 데이터가 있는 곳에서 도는 durable·비동기 백그라운드 작업.
작동 원리 (pg_durable 사례)
- DSL + duroxide 런타임을 Postgres background worker에 호스팅
df.start(...)가 즉시 instance ID를 반환하고 작업은 옆에서 실행 → 커넥션·트랜잭션을 막지 않음.df.status()/df.result()로 나중에 조회- 비동기이므로 자동으로 워크플로를 discrete step으로 분할. 각 step이 자기 세션·트랜잭션에서 돌고 진행분을 커밋한 뒤 다음으로 넘긴다 — 거대 트랜잭션을 열어두지 않는다
- step은 Postgres에 체크포인트되고 deterministic replay로 복구. 실패한 step만 재시도
- 실행 상태가 DB에 살기 때문에 DB의 durability·HA·백업·PITR을 그대로 상속한다. 이것이 외부 오케스트레이터 대비 가장 큰 구조적 이점
DSL 연산자
| 연산자 | 의미 |
|---|---|
~> | 순차 |
& | 병렬 (fan out, 전부 대기) |
| | 레이스 (먼저 끝난 것) |
?> / !> | 조건 if/else |
@> | durable 루프 (재시작을 견딤) |
|=> | step 결과를 변수로 캡처 |
df.http()(allowlist 엔드포인트), df.wait_for_schedule()(cron), df.wait_for_signal()(외부 이벤트 대기) 같은 함수가 있어 스케줄 잡과 human-in-the-loop 승인을 같은 모델로 표현한다.
언제 쓰고 언제 안 쓰는가
DB 내장 durable execution을 쓸 때 — 워크플로의 무게중심이 DB 상태에 밀착해 있을 때
- 임베딩 파이프라인 (chunk → embed, 변경분만)
- ETL 잡, 스케줄 유지보수, 큐형 백그라운드 잡
- 읽고 쓰는 row가 같은 DB에 있고, DB의 백업·PITR 우산 아래 두고 싶을 때
전용 오케스트레이터(Airflow, Temporal)를 쓸 때
- 무게중심이 Postgres 밖에 있을 때
- 이기종 서비스로 팬아웃할 때
- SQL step·분기·루프·HTTP 호출에 깔끔히 매핑되지 않는 임의의 애플리케이션 로직
AI 파이프라인과의 접점
임베딩 파이프라인은 앱 티어에서 예측 가능한 방식으로 실패한다 — 배치 중간의 일시적 API 오류에 공유 체크포인트가 없고, chunk는 썼는데 부모 row를 processed로 표시하기 전에 워커가 죽고, 바뀐 row만 재임베딩할 깔끔한 방법이 없다.
durable execution 위에 올리면 각 AI step이 durable 노드가 되어 embed()가 실패해도 chunk()를 재실행하지 않고, on_change 트리거로 변경분만 처리한다. source/steps/sink/trigger 정의와 실행 이력이 전부 SQL이 되어 기존 트랜잭션·백업·PITR의 보호를 받는다. → RAG
Idempotency와의 관계
durable execution은 idempotency를 대체하지 않고 전제한다. deterministic replay가 성립하려면 재생되는 step이 같은 입력에 같은 결과를 내야 하고, 재시도되는 step은 여러 번 실행돼도 안전해야 한다. DSL이 재시도를 자동화할수록 각 step의 idempotency 설계 책임은 오히려 커진다.
연관 개념
- Workflow Orchestration
- Idempotency
- Transactional Outbox Pattern
- Self-Healing Pipelines
- Disaggregated OLTP Architecture
- RAG