필사 모드: 내구성 워크플로우 엔진 2026 완벽 가이드 - Temporal · Restate · Hatchet · Inngest · Trigger.dev · Cadence · DBOS · Dapr Workflows 심층 분석
한국어프롤로그 — "백그라운드 잡인가, 워크플로우인가?"
2026년 어느 회사의 결제 시스템 회의.
주니어: "결제 후 메일 보내는 건 그냥 큐에 넣고 워커가 처리하면 되죠?"
시니어: "그 워커가 죽으면?"
주니어: "재시도하면 되잖아요."
시니어: "근데 메일은 이미 두 번 갔다면? 환불은 했는데 재고는 안 풀렸다면? 결제는 됐는데 주문 상태는 pending에 멈춰 있다면?"
주니어: "..."
시니어: "그게 워크플로우 엔진이 필요한 순간이야."
이 짧은 대화에 2026년 분산 시스템의 핵심 고민이 담겨 있다. Cron + Celery + Redis로 시작한 백그라운드 잡이, 결제·주문·구독·온보딩·AI 에이전트라는 **다단계 비동기 비즈니스 프로세스**로 진화하면서, 단순 큐로는 감당이 안 되는 영역이 생겼다.
**내구성 실행(durable execution)** — 코드를 짜듯이 워크플로우를 쓰지만, 그 코드의 모든 단계가 영속화돼서 프로세스가 죽었다 깨어나도 정확히 같은 자리에서 이어진다. 2026년 이 패러다임은 Temporal이 만든 카테고리에서 Restate·Hatchet·Inngest·Trigger.dev v3·DBOS가 각자의 답을 내놓는 풍성한 시장으로 변했다.
이 글은 그 전체 지형을 정리한다. 무엇이 내구성 실행인지부터, 각 엔진의 설계 철학, 코드 예제, Saga·Outbox 같은 패턴, AI 에이전트 오케스트레이션에서의 위치, 그리고 한국·일본 빅테크가 무엇을 어떻게 쓰는지까지.
1장 · 내구성 실행이란 무엇인가 — 이벤트 소싱과 리플레이
**Durable execution**의 한 줄 정의는 "함수의 모든 입출력과 비결정적 부분을 이벤트 로그에 영속화하고, 장애 후 재시작 시 로그를 리플레이해 정확히 같은 상태로 복구하는 실행 모델"이다.
이 아이디어의 뿌리는 세 가지에 있다.
1. **이벤트 소싱(event sourcing)** — 상태를 직접 저장하지 않고, 상태를 만든 사건들을 저장한다.
2. **결정적 리플레이(deterministic replay)** — 같은 이벤트 로그에 같은 코드를 돌리면 항상 같은 결과가 나와야 한다.
3. **사이드 이펙트 격리** — 외부 호출(HTTP, DB, 큐)은 한 번만 실행되고, 그 결과가 로그에 저장돼야 재실행해도 중복되지 않는다.
전통적 워크플로우 엔진(BPMN, Airflow)은 DAG 정의를 외부 파일에 두고, 엔진이 그 DAG를 해석해 실행한다. 내구성 실행은 다르다 — **워크플로우 자체가 코드**다. `if`, `for`, `try/catch`, 함수 호출이 모두 워크플로우 정의의 일부고, 엔진은 그 코드 실행을 영속화한다.
차이를 표로.
| 항목 | 전통 워크플로우(Airflow/Argo) | 내구성 실행(Temporal/Restate) |
| --- | --- | --- |
| 정의 형식 | YAML/Python DAG 선언 | 임의의 코드 |
| 분기 | DAG에 명시 | 코드의 `if/else` |
| 장기 대기 | sensor/poke | `sleep(30d)` 같은 함수 호출 |
| 상태 저장 | 외부 DB의 task 상태 | 이벤트 로그 |
| 실패 복구 | 실패한 태스크부터 재시도 | 같은 자리에서 리플레이 재개 |
| 개발 경험 | DSL 학습 | 보통의 코드 |
이 모델의 진정한 가치는 "**`sleep(30d)`가 실제로 30일을 자고 일어나도 메모리에 남아 있는 듯이 동작한다**"는 점이다. 프로세스가 죽고 다른 노드에서 다시 떠도, 이벤트 로그를 리플레이해 같은 자리로 복구된다.
2장 · 왜 지금 워크플로우 엔진이 중요한가 — 다섯 가지 문제
2026년 마이크로서비스 환경에서 워크플로우 엔진이 풀어주는 문제들.
**문제 1 — 분산 사가(distributed saga)**. 주문이 결제·재고·배송·알림 4개 서비스를 거치는데, 3단계에서 실패하면 1·2단계를 보상해야 한다. 데이터베이스 트랜잭션으로는 묶을 수 없다.
**문제 2 — 장기 실행 작업**. 회원 가입 후 7일 트라이얼, 14일 후 결제, 30일 후 만료 — 이 타임라인은 메모리에 들고 있을 수 없고, cron + state machine으로 짜면 코드가 폭주한다.
**문제 3 — AI 파이프라인**. RAG 인덱싱 → 임베딩 → 생성 → 검토 → 게시 같은 다단계 LLM 파이프라인은 단계별 실패율이 다르고, 일부는 분 단위로 오래 걸리며, 비용이 큰 단계는 절대 중복 호출하면 안 된다.
**문제 4 — 멱등성과 재시도**. 외부 API(결제, 메일, SMS)는 네트워크 단절 시 멱등성 키 없이는 재시도가 위험하다. 워크플로우 엔진은 그 멱등 처리를 코드 한 줄로 추상화한다.
**문제 5 — 정확히 한 번(exactly-once)**. 메시지 큐로 흉내 낼 수 있는 "at-least-once + 멱등성"의 한계를 넘어, "각 비즈니스 액션은 정확히 한 번 일어났음"을 강제하는 게 워크플로우 엔진의 코어 약속이다.
요컨대, 2026년 백엔드 엔지니어가 풀어야 할 문제가 점점 "한 번의 HTTP 응답" 모양이 아니라 "여러 시스템을 가로지르며 시간을 가로지르는 프로세스" 모양이라는 것이다.
3장 · Temporal Cloud + Temporal Server 1.25 — 카테고리 정의자
Temporal은 2019년 Maxim Fateev와 Samar Abbas(둘 다 Uber Cadence 원작자)가 창업한 회사로, 사실상 "내구성 실행"이라는 카테고리를 정의했다. 2025년 시리즈 D로 평가가 15억 달러를 넘었다.
핵심 아키텍처.
| 구성 요소 | 역할 |
| --- | --- |
| Frontend | gRPC API gateway |
| History | 이벤트 로그 영속화 (Cassandra/PostgreSQL/MySQL) |
| Matching | 태스크 큐 |
| Worker (Internal) | 시스템 워크플로우(예: 아카이브) |
| **Worker (User)** | 사용자가 SDK로 작성한 워크플로우/액티비티를 실행 |
Temporal Server 1.25(2025년 후반)의 큰 변화.
- **PostgreSQL 16 지원 + 새로운 visibility 백엔드**(ElasticSearch 의존성 줄임).
- **Update with start** — 워크플로우를 시작과 동시에 입력을 전달.
- **Nexus** — 서로 다른 namespace 간 시그널/쿼리를 안전하게 (멀티테넌시).
- **워크플로우 메모이제이션 캐시 개선** — 메모리 사용 50% 절감.
SDK는 Go·Java·Python·.NET·TypeScript·PHP·Ruby가 공식이고, 2025년 Rust SDK가 베타로 추가됐다. 가장 사랑받는 건 TypeScript와 Python.
**TypeScript 워크플로우 예시**.
// workflows/order.ts
const { chargeCard, reserveInventory, ship, sendEmail, refundCard } =
proxyActivities<typeof activities>({ startToCloseTimeout: '1 minute' })
export const cancelOrderSignal = defineSignal('cancelOrder')
export async function orderWorkflow(orderId: string, amount: number) {
let cancelled = false
setHandler(cancelOrderSignal, () => { cancelled = true })
await chargeCard(orderId, amount)
try {
await reserveInventory(orderId)
await ship(orderId)
await sleep('48 hours') // 배송 후 48시간 후 만족도 메일
if (!cancelled) await sendEmail(orderId, 'satisfaction-survey')
} catch (err) {
await refundCard(orderId, amount) // 보상 액션
throw err
}
}
이 코드의 마법은 `sleep('48 hours')`다. 워커가 죽었다 다시 떠도, 다른 호스트에서 다시 시작해도, 48시간 후의 그 시점에 정확히 다음 줄로 이어진다.
워커 실행.
// worker.ts
const worker = await Worker.create({
workflowsPath: require.resolve('./workflows'),
activities,
taskQueue: 'orders',
})
await worker.run()
**Temporal Cloud**는 매니지드 형태로, 2026년 가격은 액션(이벤트) 기반 + active execution. 일반적인 SaaS는 클러스터 자체 운영보다 Cloud가 싸다.
4장 · Cadence (Uber) — Temporal의 조상
Cadence는 2017년 Uber가 오픈소스화한 워크플로우 엔진으로, Temporal의 직계 조상이다. Temporal 공동창업자들이 원래 Uber Cadence 팀을 이끌었고, 2019년 Temporal로 fork·창업했다.
2026년 시점에서 두 시스템의 관계.
- **API/SDK는 유사**하지만 호환되지 않음. Cadence Go SDK 코드를 Temporal로 옮기려면 패키지명·일부 시맨틱을 손봐야 함.
- **Cadence는 여전히 Uber 내부에서 거대 규모로 운영** 중 (수십만 워크플로우 인스턴스/일).
- **Temporal이 OSS 측 혁신을 주도** — Nexus, Workflow Updates, Visibility v2 등 새 기능은 Temporal에서 먼저 나온다.
새 프로젝트라면 Temporal을 권한다. Cadence는 Uber 생태계 또는 기존 Cadence 자산이 있는 곳에서만 유의미.
5장 · Restate — Workflow + RPC, "더 단순한 Temporal"
Restate는 2023년 Stephan Ewen(Apache Flink 공동창업자)이 창업한 회사로, 2025년 1.0이 출시됐다.
설계 결정의 차이.
| 항목 | Temporal | Restate |
| --- | --- | --- |
| 핵심 추상 | 워크플로우 + 액티비티 | 가상 객체(virtual object) + 워크플로우 + 서비스 |
| 영속 저장 | Cassandra/Postgres | 내장 RocksDB + 임의 외부 저장소 |
| 통신 | gRPC + 자체 프로토콜 | HTTP/2 + Connect/gRPC 프로토콜 |
| 배포 | 클러스터(History/Matching/...) | 단일 바이너리 |
| 결정성 | SDK가 보장 | 핸들러 단위 멱등성 |
Restate의 핵심 키워드는 **가상 객체**다. 무상태 핸들러(HTTP 엔드포인트)와 영속 상태를 결합한 단위로, "결제 도메인 객체" 같은 모델을 자연스럽게 표현한다.
**TypeScript 예시**.
const orderService = restate.service({
name: 'OrderService',
handlers: {
async place(ctx: restate.Context, input: { orderId: string; amount: number }) {
const paymentId = await ctx.run('charge', () =>
chargeAPI(input.orderId, input.amount)
)
try {
await ctx.run('reserve', () => reserveInventory(input.orderId))
} catch (err) {
await ctx.run('refund', () => refundAPI(paymentId))
throw err
}
await ctx.sleep(48 * 60 * 60 * 1000) // 48h
await ctx.run('survey', () => sendSurveyEmail(input.orderId))
},
},
})
restate.endpoint().bind(orderService).listen(9080)
`ctx.run(...)`이 사이드 이펙트의 멱등 단위다. 결과가 Restate 서버에 영속화되고, 재실행 시 같은 결과를 그대로 반환한다.
Restate의 매력은 **운영 단순성**이다. 단일 Rust 바이너리, 별도의 SQL 또는 Cassandra 클러스터 없이도 작은 규모는 그대로 동작. AWS·GCP·Azure 매니지드도 베타로 등장 중.
2026년 Restate의 포지셔닝은 "**Temporal의 강력함은 필요한데, 운영 복잡성은 싫은 팀**" 이다. 작은 스타트업이나 단일 서비스에 빠르게 도입하려는 곳에서 채택이 늘었다.
6장 · Hatchet — Postgres 위의 분산 큐 + 워크플로우
Hatchet은 2023년 등장한 오픈소스 워크플로우 엔진으로, **Postgres만으로 동작**한다는 게 핵심 차별점이다.
설계 선언.
- 외부 의존성은 Postgres 하나. Cassandra·Redis·NATS·Kafka 안 씀.
- gRPC + 워커 SDK (Python·TypeScript·Go).
- 멀티테넌시 내장.
- AOR(Acyclic Orchestration Runtime) — DAG처럼 단계를 정의.
**Python 예시**.
from hatchet_sdk import Hatchet, Context
hatchet = Hatchet()
@hatchet.workflow(on_events=["order:created"])
class OrderWorkflow:
@hatchet.step(retries=3, timeout="1m")
def charge(self, ctx: Context):
order = ctx.workflow_input()
return charge_card(order["id"], order["amount"])
@hatchet.step(parents=["charge"])
def reserve(self, ctx: Context):
return reserve_inventory(ctx.workflow_input()["id"])
@hatchet.step(parents=["reserve"])
def ship(self, ctx: Context):
return ship_order(ctx.workflow_input()["id"])
worker = hatchet.worker("orders-worker")
worker.register_workflow(OrderWorkflow())
worker.start()
Hatchet의 강점은 **이미 Postgres를 쓰고 있는 팀**에게 절대 매력적이라는 점이다. 새 인프라 없이 비동기 잡 + 워크플로우 + 큐를 한 시스템으로 통합. 게다가 Python 인기 분야(데이터·AI)에서 빠르게 자리잡았다.
2026년 Hatchet Cloud도 출시돼 매니지드 옵션이 추가됐다.
7장 · Inngest — Step Functions, 개발자 우선
Inngest는 2021년 등장해, "**개발자에게 Step Functions의 정확성을, AWS 락인 없이**" 를 슬로건으로 자리 잡았다. TypeScript 우선 SDK가 가장 잘 만들어졌다는 평가.
핵심 추상은 `step`이다. 함수 안에서 `step.run`, `step.sleep`, `step.sendEvent`, `step.waitForEvent`로 영속 단위를 정의하면, Inngest 엔진이 각 step의 입출력을 저장하고 재실행 시 캐시된 값을 재사용한다.
**TypeScript 예시**.
export const onboarding = inngest.createFunction(
{ id: 'user-onboarding' },
{ event: 'user.signed_up' },
async ({ event, step }) => {
await step.run('send-welcome-email', () => sendEmail(event.data.email, 'welcome'))
await step.sleep('wait-2-days', '2 days')
await step.run('send-tips', () => sendEmail(event.data.email, 'tips'))
const purchase = await step.waitForEvent('await-purchase', {
event: 'order.completed',
timeout: '7d',
match: 'data.userId',
})
if (!purchase) {
await step.run('reminder', () => sendEmail(event.data.email, 'reminder'))
}
}
)
이 코드는 사용자 가입 후 7일짜리 온보딩을 그대로 표현한다. `step.waitForEvent`로 특정 이벤트 도착을 기다리는 게 자연스럽다.
Inngest의 매력은 **다섯 가지가 한 곳에 합쳐졌다**는 것 — 이벤트 큐, 크론, 워크플로우, 함수 호스팅, 옵저버빌리티. 별도의 BullMQ/Sidekiq + Temporal 조합을 한 SaaS로 끝낸다.
가격은 함수 호출(steps) 기반. 작은 스타트업은 무료 티어로 충분히 시작 가능.
8장 · Trigger.dev v3 — 오픈소스 Inngest 대안
Trigger.dev는 2022년 시작했고, v2까지는 SaaS 중심이었다. 2024년 출시된 **v3가 큰 전환**이다.
- **오픈소스화**: AGPL 라이선스로 자체 호스팅 가능.
- **컨테이너 기반 실행**: 작업을 Firecracker 또는 Docker에서 격리 실행.
- **체크포인팅**: 작업 중간에 메모리 스냅샷을 떠서, 긴 작업을 재개 가능.
- **TypeScript 우선**.
**예시**.
export const onboarding = task({
id: 'user-onboarding',
maxDuration: 60 * 60 * 24 * 7, // 7d
run: async (payload: { userId: string; email: string }) => {
await sendEmail(payload.email, 'welcome')
await wait.for({ days: 2 })
await sendEmail(payload.email, 'tips')
const purchase = await wait.forEvent('order.completed', {
timeout: '5d',
filter: (e: any) => e.userId === payload.userId,
})
if (!purchase) {
await sendEmail(payload.email, 'reminder')
}
},
})
Trigger.dev v3의 차별 포인트는 **체크포인팅**이다. 임의의 npm 라이브러리를 호출해도 (예: Puppeteer로 PDF 생성) 중간에 컨테이너를 정지·재개할 수 있다. AI 추론처럼 GPU 자원을 쓰는 작업에 특히 어울린다.
Inngest와 Trigger.dev의 차이.
| 항목 | Inngest | Trigger.dev v3 |
| --- | --- | --- |
| 라이선스 | 비공개(코어 OSS 일부) | AGPL |
| 실행 모델 | 사용자 함수가 HTTP로 호출됨 | Trigger 컨테이너가 사용자 코드를 실행 |
| 자체 호스팅 | 제한적 | 완전 가능 |
| 가격 | step 기반 | 컴퓨트 시간 |
| AI/긴 작업 | 가능하지만 step 분할 필요 | 체크포인팅으로 자연스러움 |
9장 · DBOS — Postgres가 곧 런타임
DBOS는 2023년 MIT의 Mike Stonebraker(PostgreSQL·Vertica·VoltDB) 그룹이 창업했다. 한 줄 요약: "**프로그램 상태를 Postgres에 영속화하는 런타임**".
DBOS의 발상은 이렇다 — 모든 함수 호출, 트랜잭션, 워크플로우 단계의 입출력을 Postgres에 저장한다. 그러면 함수 자체가 **transactional**이고, 실패 후 재시작도 같은 Postgres 트랜잭션 정합성으로 보장된다.
**Python 예시**.
from dbos import DBOS, Queue, WorkflowHandle
from sqlalchemy import text
DBOS()
@DBOS.workflow()
def order_workflow(order_id: str, amount: int):
payment_id = charge_step(order_id, amount)
try:
reserve_step(order_id)
ship_step(order_id)
except Exception:
refund_step(payment_id)
raise
@DBOS.transaction()
def charge_step(order_id: str, amount: int):
DBOS.sql_session.execute(
text("INSERT INTO payments(order_id, amount) VALUES (:o, :a)"),
{"o": order_id, "a": amount},
)
return f"pay-{order_id}"
`@DBOS.workflow()`와 `@DBOS.transaction()` 데코레이터로 영속 단위를 명시한다. 트랜잭션 액티비티는 Postgres에 직접 쓰고, 그 트랜잭션이 워크플로우 상태 업데이트와 같은 트랜잭션에 묶인다 — **DB 정합성 + 워크플로우 정합성 통일**.
2026년 DBOS는 **Postgres 위에서 모든 걸 끝내고 싶은 팀**에서 인기. 단점은 Postgres에 종속된다는 점, 그리고 매우 큰 처리량 워크로드에서 Postgres가 병목이 될 수 있다는 점.
10장 · Dapr Workflows — 쿠버네티스 네이티브 사이드카
Dapr는 마이크로소프트가 2019년 오픈소스화한 마이크로서비스 런타임으로, **사이드카 패턴**(애플리케이션 옆에 Dapr 사이드카가 붙어 상태/큐/이벤트 추상화 제공)이 핵심이다. 2022년 CNCF 졸업.
**Dapr Workflows**는 Dapr 1.10에서 알파로 등장, 1.13(2024)에서 안정화됐다. 내부적으로 **DurableTask** 라이브러리(Azure Durable Functions 코어)를 채택했다.
특징.
- **언어 SDK**: Go·.NET·Python·Java·JavaScript.
- **백엔드 추상화**: state store는 Redis·Postgres·Cosmos DB 등 임의 선택.
- **쿠버네티스에 자연스럽게 통합**: Dapr가 K8s 사이드카로 동작.
**Python 예시**.
from dapr.ext.workflow import WorkflowRuntime, DaprWorkflowContext, WorkflowActivityContext
wfr = WorkflowRuntime()
@wfr.workflow(name="order")
def order_workflow(ctx: DaprWorkflowContext, order: dict):
payment = yield ctx.call_activity(charge, input=order)
try:
yield ctx.call_activity(reserve, input=order)
yield ctx.create_timer(fire_at=ctx.current_utc_datetime + timedelta(hours=48))
yield ctx.call_activity(send_survey, input=order)
except Exception:
yield ctx.call_activity(refund, input=payment)
raise
@wfr.activity(name="charge")
def charge(ctx: WorkflowActivityContext, order: dict):
return charge_card_api(order["id"], order["amount"])
Dapr Workflows의 강점은 **Dapr를 이미 쓰고 있는 K8s 환경에서 추가 인프라 없이 도입 가능**하다는 점. state store만 정해 두면 동일 코드로 백엔드 교체 가능.
약점은 다른 런타임 대비 SDK 완성도와 옵저버빌리티가 아직 한 단계 뒤라는 것.
11장 · AWS Step Functions — 매니지드의 표준
AWS Step Functions(2016년 출시)는 워크플로우 매니지드 서비스의 사실상 표준이다. **JSON으로 정의된 상태 머신**이 핵심.
종류.
| 종류 | 가격 | 용도 |
| --- | --- | --- |
| Standard | 상태 전이당 ($0.025/1000) | 장기 실행, 최대 1년, 정확히 한 번 보장 |
| Express | 실행 시간 + 메모리 | 단기, 최대 5분, at-least-once |
**ASL(Amazon States Language) 예시**.
{
"StartAt": "ChargeCard",
"States": {
"ChargeCard": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": { "FunctionName": "charge-card", "Payload.$": "$" },
"Next": "Reserve"
},
"Reserve": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": { "FunctionName": "reserve-inventory", "Payload.$": "$" },
"Catch": [{ "ErrorEquals": ["States.ALL"], "Next": "Refund" }],
"Next": "Wait48h"
},
"Wait48h": { "Type": "Wait", "Seconds": 172800, "Next": "Survey" },
"Survey": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": { "FunctionName": "send-survey", "Payload.$": "$" },
"End": true
},
"Refund": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": { "FunctionName": "refund-card", "Payload.$": "$" },
"End": true
}
}
}
AWS 락인이 큰 대신 **운영 부담이 사실상 없다**. AWS 생태계의 모든 서비스(Lambda·DynamoDB·SQS·Bedrock·Athena·Glue)와 직접 통합돼 SDK 호출이 한 줄.
비용 함정. Standard는 상태 전이가 많은 워크플로우에서 빠르게 비싸진다. 수백만 실행 + 수십 step이면 월 수천 달러를 쉽게 넘긴다. Express + Map state로 비용 최적화하는 게 표준.
12장 · GCP Workflows + Azure Durable Functions
**Google Cloud Workflows** (2020).
- YAML 또는 JSON 정의.
- HTTP 호출 + 분기 + 병렬.
- Eventarc, Cloud Run, Cloud Functions와 자연스러운 통합.
- 가격: step 실행당.
- 단점: 상태 머신 표현력이 Step Functions보다 단순.
**Azure Durable Functions** (2017).
- Azure Functions의 확장.
- **C#/JavaScript/Python**으로 코드처럼 워크플로우 작성.
- 내구성 실행 진영의 원조 격 — Temporal의 일부 아이디어가 여기서 영감받음.
- DurableTask(오픈소스) 라이브러리가 Dapr Workflows의 코어.
**TypeScript Durable Function 예시**.
df.app.orchestration('orderWorkflow', function* (ctx) {
const order = ctx.df.getInput()
const payment = yield ctx.df.callActivity('chargeCard', order)
try {
yield ctx.df.callActivity('reserveInventory', order)
yield ctx.df.createTimer(new Date(Date.now() + 48 * 3600 * 1000))
yield ctx.df.callActivity('sendSurvey', order)
} catch {
yield ctx.df.callActivity('refundCard', payment)
throw new Error('order failed')
}
})
`yield`마다 체크포인트가 생성된다. 클라우드 락인이지만 정형화돼 있고, Azure 사용자라면 표준 선택.
13장 · Airflow + Dagster + Prefect — 데이터 엔지니어링 DAG
데이터 파이프라인 영역에는 별도의 DAG 엔진이 자리 잡고 있다. 본 글의 범위는 아니지만 비교 차원에서 짚는다.
| 엔진 | 시작 | 강점 | 약점 |
| --- | --- | --- | --- |
| Apache Airflow | 2014 (Airbnb) | 가장 많이 쓰임, 풍부한 연결자 | Python DAG 정의, 동적 워크플로우 약함 |
| Dagster | 2018 | 자산 중심(asset graph), 타입 시스템 | 학습 곡선 |
| Prefect | 2018 | Pythonic API, 동적 워크플로우 | 작은 커뮤니티 |
| Argo Workflows | 2018 | K8s 네이티브, CI/CD에 강함 | Pod 오버헤드 |
데이터 엔지니어링 DAG와 내구성 실행의 결정적 차이.
- **DAG 엔진**: 데이터 자산 변환 그래프, 시간 단위 트리거가 중심.
- **내구성 실행**: 비즈니스 프로세스, 이벤트·시간·시그널이 혼재된 코드 흐름.
2026년 패턴은 "**DAG는 데이터 파이프라인용, 내구성 실행은 비즈니스 로직용**" 으로 분업이 굳어졌다.
14장 · Argo Workflows — 쿠버네티스 CI/CD
Argo Workflows는 2017년 Applatix(인튜이트 인수)가 오픈소스화한 CNCF 졸업 프로젝트로, **모든 단계가 K8s Pod**다.
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata: { generateName: build-and-deploy- }
spec:
entrypoint: pipeline
templates:
- name: pipeline
steps:
- - name: build
template: build
- - name: test
template: test
- - name: deploy
template: deploy
- name: build
container: { image: golang:1.23, command: ["go", "build", "./..."] }
- name: test
container: { image: golang:1.23, command: ["go", "test", "./..."] }
- name: deploy
container: { image: argoproj/argocd:v2.12, command: ["argocd", "app", "sync", "main"] }
Argo Workflows는 **K8s 네이티브 CI/CD**의 표준. ML 파이프라인(Kubeflow Pipelines가 Argo 기반), 빌드/배포(Argo CD와 결합), 데이터 파이프라인에 두루 쓰인다.
내구성 실행과의 위치 차이: Argo는 **컨테이너 오케스트레이션 워크플로우**, Temporal/Restate는 **언어 내 영속 실행**. 같은 자리에 둘 다 쓰는 경우도 많다.
15장 · Cloudflare Workflows — Workers + Durable Objects
Cloudflare Workflows는 2024년 9월 베타로 출시됐다. 핵심은 **Cloudflare Workers 위에서 동작하는 내구성 워크플로우**라는 점.
export class OrderWorkflow extends WorkflowEntrypoint<Env, { orderId: string; amount: number }> {
async run(event: WorkflowEvent<{ orderId: string; amount: number }>, step: WorkflowStep) {
const payment = await step.do('charge', async () =>
chargeCard(event.payload.orderId, event.payload.amount)
)
try {
await step.do('reserve', async () => reserveInventory(event.payload.orderId))
await step.sleep('wait 48h', '48 hours')
await step.do('survey', async () => sendSurvey(event.payload.orderId))
} catch (err) {
await step.do('refund', async () => refundCard(payment))
throw err
}
}
}
엣지 컴퓨팅 + 내구성 실행의 조합. 글로벌 엣지에서 실행되므로 지연이 매우 낮고, Durable Objects가 영속 상태를 책임진다. 2026년 GA를 향해 가는 중.
16장 · Conductor (Netflix → Orkes 2022) — JSON DSL
Conductor는 2016년 Netflix가 오픈소스화한 워크플로우 엔진으로, **JSON DSL** 기반이다. 2022년 핵심 팀이 Orkes로 분사해 매니지드 서비스를 운영 중.
{
"name": "order_workflow",
"version": 1,
"tasks": [
{ "name": "charge_card", "type": "SIMPLE", "taskReferenceName": "charge" },
{ "name": "reserve_inventory", "type": "SIMPLE", "taskReferenceName": "reserve" },
{
"name": "wait_48h", "type": "WAIT", "taskReferenceName": "wait48",
"inputParameters": { "duration": "48h" }
},
{ "name": "send_survey", "type": "SIMPLE", "taskReferenceName": "survey" }
]
}
Conductor의 강점은 **언어 중립**이다. JSON DSL + 워커가 어떤 언어로든 가능. Netflix 내부 수천 개의 워크플로우를 운영한 실전 검증이 있다.
약점은 DSL 학습이 별도로 필요하다는 것. 2026년 Conductor는 큰 엔터프라이즈(Netflix 외에도 Walmart·Tesla 인용)에서 쓰이지만, 스타트업 채택은 Temporal/Inngest에 밀린다.
17장 · Zeebe + Camunda 8 — BPMN 기반
Camunda는 2008년 시작한 워크플로우 회사로, 2022년 Camunda 8과 함께 **Zeebe** 엔진(클라우드 네이티브, gRPC)을 메인으로 채택했다.
핵심 특징.
- **BPMN 2.0**: 비즈니스가 이해할 수 있는 시각적 표기.
- **DMN**: 의사결정 테이블.
- **클러스터링**: Zeebe broker + Elasticsearch로 클러스터 구성.
BPMN은 비즈니스/마케팅/오퍼레이션 팀과 워크플로우를 협업하기 좋다. 보험·은행·통신에서 채택률이 높다. 엔지니어가 코드로 짜고 싶다면 Temporal/Restate가 자연스럽고, **비즈니스가 다이어그램으로 본다**가 중요하면 Camunda가 맞다.
18장 · 사가(Saga) 패턴 — 분산 보상 트랜잭션
내구성 워크플로우의 단골 패턴은 **사가**다.
| 단계 | 액션 | 보상 |
| --- | --- | --- |
| 1 | 결제 | 환불 |
| 2 | 재고 차감 | 재고 복원 |
| 3 | 배송 | 배송 취소 |
| 4 | 알림 | (없음) |
3단계에서 실패하면 2 → 1 순으로 보상 액션을 역순 실행. 워크플로우 엔진은 이 흐름을 `try/catch + 보상 호출`로 쉽게 표현한다.
**Temporal에서 사가**.
const { charge, refund, reserve, restore, ship, cancel, notify } =
proxyActivities<typeof activities>({ startToCloseTimeout: '1 minute' })
export async function saga(orderId: string, amount: number) {
const compensations: Array<() => Promise<void>> = []
try {
await charge(orderId, amount)
compensations.push(() => refund(orderId, amount))
await reserve(orderId)
compensations.push(() => restore(orderId))
await ship(orderId)
compensations.push(() => cancel(orderId))
await notify(orderId)
} catch (err) {
for (const compensate of compensations.reverse()) await compensate()
throw err
}
}
**보상의 멱등성**이 핵심. `refund(orderId)`가 두 번 호출돼도 두 번 환불하면 안 된다.
19장 · Outbox 패턴과 멱등성 키
워크플로우 엔진이 풀어주지 못하는(혹은 풀어주는) 두 가지 정합성 도구.
**Outbox 패턴** — DB 트랜잭션과 메시지 발송을 묶기 위해, 비즈니스 변경과 같은 트랜잭션에 "이벤트 보낼 거" 레코드를 outbox 테이블에 쓴다. 별도 디스패처가 outbox 테이블을 읽어 메시지 큐로 보낸다. DBOS는 이 패턴이 자연스럽고, Temporal에서는 활동에서 직접 outbox 테이블에 INSERT 하는 식으로 결합.
BEGIN;
UPDATE orders SET status='paid' WHERE id='o1';
INSERT INTO outbox(topic, payload) VALUES ('order.paid', '{"id":"o1"}');
COMMIT;
**멱등성 키(idempotency key)** — 외부 API(특히 결제) 호출 시 같은 요청을 두 번 보내도 한 번만 처리되도록 키를 함께 전달. Stripe·Adyen·PayPal API는 모두 이 패턴을 지원.
curl -X POST https://api.stripe.com/v1/charges \
-H "Idempotency-Key: order-o1-charge" \
-d amount=10000 -d currency=usd -d source=tok_visa
Temporal/Restate/Inngest는 워크플로우 ID 또는 step ID를 자연스럽게 멱등성 키로 활용. `Idempotency-Key: ${workflowId}-${stepName}` 같은 식.
20장 · 지수 백오프 재시도와 데드 레터
모든 워크플로우 엔진의 표준 기능은 **지수 백오프 재시도**. Temporal RetryPolicy 예시.
const { charge } = proxyActivities<typeof activities>({
startToCloseTimeout: '30 seconds',
retry: {
initialInterval: '1 second',
backoffCoefficient: 2,
maximumInterval: '1 minute',
maximumAttempts: 5,
nonRetryableErrorTypes: ['ValidationError'],
},
})
5번 실패하면 워크플로우는 실패 상태로 가고, 운영자가 수동으로 재시작하거나 데드 레터 큐로 옮긴다. Inngest는 이 자동 데드 레터를 기본 제공.
비결정적 오류(타임아웃, 네트워크)는 재시도해도 되지만, **결정적 오류**(검증 실패, 잘못된 입력)는 재시도해도 똑같이 실패한다. `nonRetryableErrorTypes`로 분리하는 게 표준.
21장 · AI 에이전트 오케스트레이션 — LangGraph · Claude · OpenAI Agents
2025~2026년 가장 빠르게 자라는 워크플로우 활용 영역은 **AI 에이전트**다. 다단계 LLM 파이프라인은 모든 내구성 실행의 매력 — 단계별 비용, 단계별 실패, 멱등성 — 이 그대로 적용된다.
**LangGraph** (LangChain 자매 프로젝트, 2024~). 그래프 기반 에이전트 워크플로우. 노드와 엣지로 상태 머신을 구성.
from langgraph.graph import StateGraph, END
from typing import TypedDict
class State(TypedDict):
question: str
answer: str
graph = StateGraph(State)
graph.add_node("retrieve", lambda s: {"answer": rag(s["question"])})
graph.add_node("review", lambda s: {"answer": review(s["answer"])})
graph.add_edge("retrieve", "review")
graph.add_edge("review", END)
graph.set_entry_point("retrieve")
app = graph.compile()
LangGraph 자체는 "그래프 정의 + 인메모리 런타임"이지만, **LangGraph Cloud**에서 체크포인트 저장과 재개를 제공해 내구성 실행에 가까워진다.
**Anthropic Claude Agent SDK** (2025). 도구 사용 + 핸드오프 기반. Temporal/Restate와 결합해 도구 호출을 액티비티로 래핑하면 자연스러운 내구성 에이전트가 된다.
**OpenAI Agents SDK** (2025). 비슷한 핸드오프 모델. 단일 에이전트가 다른 에이전트로 작업 전달.
세 SDK의 공통점은 **에이전트 자체는 내구성 보장이 약하고**, 그래서 Temporal/Restate/Inngest를 백엔드로 깔아 영속성을 책임지는 패턴이 표준이 되어가고 있다.
22장 · 비교 매트릭스 — 무엇을 언제 고를까
| 엔진 | OSS | 운영 복잡도 | SDK | 강점 | 약점 |
| --- | --- | --- | --- | --- | --- |
| Temporal | Yes (MIT) | 중상 | Go·Java·Py·.NET·TS·PHP·Rust | 가장 강력, 대규모 검증 | Cassandra/PG·운영 부담, 클라우드는 비쌀 수 있음 |
| Restate | Yes (BSL) | 하 | Go·Java·TS·Py·Rust·Kotlin | 운영 단순, 가상 객체 | 신규, 생태계 작음 |
| Hatchet | Yes (MIT) | 하 | Py·TS·Go | Postgres 기반 단순 | 신규, 큰 규모 검증 부족 |
| Inngest | 일부 | 매니지드 | TS·Py·Go | 개발 경험 최고 | 자체 호스팅 제한 |
| Trigger.dev v3 | Yes (AGPL) | 중 | TS | OSS + 체크포인팅 | 컨테이너 오버헤드 |
| DBOS | Yes (MIT) | 하 | Py·TS | Postgres 트랜잭션 통합 | PG 의존, 처리량 한계 |
| Dapr Workflows | Yes (Apache 2.0) | 중 | Go·.NET·Py·Java·JS | K8s·Dapr 생태계 | SDK 성숙도 낮음 |
| AWS Step Functions | No | 매니지드 | JSON DSL | AWS 통합, 운영 0 | AWS 락인, 비용 |
| Azure Durable | No | 매니지드 | C#·JS·Py·Java | Azure 통합 | Azure 락인 |
| GCP Workflows | No | 매니지드 | YAML | GCP 통합 | 표현력 낮음 |
| Cadence | Yes (MIT) | 중상 | Go·Java | Uber 검증 | Temporal에 밀리는 추세 |
| Conductor | Yes (Apache 2.0) | 중 | 언어 중립 워커 | JSON DSL, 언어 중립 | DSL 학습 |
| Camunda 8 / Zeebe | 일부 | 중상 | BPMN + 클라이언트 | BPMN, 비즈니스 협업 | 무거움 |
| Cloudflare Workflows | No | 매니지드 | TS | 엣지 + 워커 | 베타, 단기 작업 위주 |
**한 줄 가이드**.
- "현실 검증된, 가장 강력한" → Temporal.
- "운영 단순함, 비슷한 표현력" → Restate.
- "Postgres만 쓰고 싶다" → Hatchet 또는 DBOS.
- "TS 코드로 빠르게, 매니지드" → Inngest.
- "OSS 매니지드 대안, 긴 작업/AI" → Trigger.dev v3.
- "AWS만 쓰는데 운영 0" → Step Functions.
- "K8s + Dapr 환경" → Dapr Workflows.
- "비즈니스 BPMN 협업" → Camunda 8.
23장 · 한국 빅테크 채택 사례
**토스(Toss)** — 금융 거래의 내구성 트랜잭션에 내부 워크플로우 엔진을 구축, 2024년 컨퍼런스에서 Temporal 도입 경험을 발표(2023~). 결제·정산·이체 도메인에서 사가 패턴 활용.
**쿠팡(Coupang)** — 주문 파이프라인의 다단계 처리에 내부 워크플로우 엔진과 AWS Step Functions를 혼용. 새 마이크로서비스에서는 Temporal 도입을 평가 중.
**네이버(Naver)** — Naver Cloud 내부 자동화에 Argo Workflows + 자체 엔진. 검색·쇼핑의 배치 처리는 자체 분산 잡 시스템.
**NC소프트(NCsoft)** — 게임 상태 머신, 길드 이벤트 등 장기 비동기 처리에 Cadence/Temporal류 검토 사례 공유.
**라인플러스 / LY** — 메시지·결제·광고의 비동기 처리에 Kafka + 자체 워크플로우 엔진. 일부 도메인은 Temporal POC 진행.
**카카오** — 카카오톡 알림·결제 파이프라인. 자체 비동기 처리 인프라가 강하고, 새 도메인에는 Temporal·Inngest 평가.
공통점은 **결제와 주문 영역**에서 가장 먼저 내구성 실행 도입을 검토한다는 점. 트랜잭션 정합성 + 보상 + 운영 가시성을 동시에 풀어야 하기 때문.
24장 · 일본 빅테크 채택 사례
**Mercari** — 결제·송금 도메인에 자체 워크플로우 엔진과 일부 Temporal POC. 마이크로서비스화가 가장 진전된 사례로 알려져 있다.
**LINE Yahoo (LY Corporation)** — 합병 후 통합 주문/결제 파이프라인 구축에 Kafka + 워크플로우 엔진을 혼용. 자체 엔진 + 부분적으로 Temporal.
**Rakuten** — 공급망·구독·포인트 시스템. AWS Step Functions와 Apache Airflow가 두 축, 새 도메인은 Temporal Cloud 평가.
**Recruit** — Indeed/SUUMO 등 자회사가 다양. 일부 팀은 Inngest, 일부는 Airflow + 자체 DAG.
**SmartHR / freee** — SaaS HR/회계. 비동기 잡 + 워크플로우 통합에 Temporal·Inngest를 활발히 검토.
**NTT Data** — 엔터프라이즈 통합에 Camunda BPMN 채택률 높음.
일본 시장의 특징: 엔터프라이즈에서는 BPMN(Camunda) 채택률이 한국·미국보다 상대적으로 높다. 스타트업/모던 SaaS에서는 Temporal·Inngest가 빠르게 자리잡는 중.
25장 · 시작하기 — 30분 안에 첫 내구성 워크플로우
가장 빠른 시작은 Temporal CLI + TypeScript 예제.
1. Temporal Server 띄우기
brew install temporal
temporal server start-dev
2. 새 프로젝트
npx @temporalio/create@latest hello-temporal
cd hello-temporal
3. 워커 + 클라이언트
npm install
npm run start.watch # 워커
npm run workflow # 워크플로우 실행
Inngest는 더 빠르다.
npx inngest-cli@latest dev
별도 터미널
mkdir hello-inngest && cd $_
npm init -y
npm install inngest
Restate.
docker run -d --name restate -p 8080:8080 -p 9070:9070 docker.restate.dev/restatedev/restate:latest
npm install @restatedev/restate-sdk
세 엔진의 첫 워크플로우는 모두 30분 내. 그 다음은 자기 도메인의 가장 골치 아픈 비동기 흐름 하나를 골라 옮겨보는 것 — "결제 → 환불", "회원 가입 → 트라이얼 만료", "AI 인덱싱 → 검토" 같은.
26장 · 안티패턴과 흔한 실수
내구성 워크플로우를 잘못 쓰는 흔한 케이스.
**1. 모든 걸 워크플로우로 만들기**. 단순 백그라운드 잡(이메일 1개 발송)에는 BullMQ/Sidekiq/Celery로 충분. 워크플로우 엔진은 "다단계 + 시간 가로지름 + 보상 필요"에 어울린다.
**2. 결정성 깨기**. 워크플로우 코드 안에서 직접 `Date.now()`, `Math.random()`, `fetch(...)`를 호출하면 리플레이가 깨진다. 항상 `proxyActivities` / `ctx.run` / `step.run`을 통해서.
**3. 큰 페이로드 전달**. 워크플로우 입출력은 이벤트 로그에 저장된다. MB 단위 페이로드는 로그가 폭주. S3 키만 전달하고 액티비티 안에서 읽는 게 표준.
**4. 워크플로우 안에서 무한 루프**. `while(true)`로 폴링하지 마라. Temporal은 `continueAsNew`, Restate는 새 세션, Inngest는 새 이벤트로 워크플로우를 갱신.
**5. 보상 누락**. 사가의 본질은 보상이다. "보상 액션이 실패하면?"이라는 질문을 항상 함께 답하라.
**6. 시그널 폭주**. 시그널은 워크플로우의 상태를 비결정적으로 만들 수 있다. 시그널 처리 순서와 idempotency를 신중히.
**7. 매니지드 비용 무시**. Temporal Cloud / Step Functions는 액션 단위 과금이다. 1초마다 폴링하는 워크플로우는 한 달에 수천 달러를 쉽게 넘긴다.
27장 · 마치며 — "코드처럼 워크플로우를"
2026년 워크플로우 엔진의 큰 흐름.
1. **코드 중심으로 통일**. JSON/YAML/BPMN DSL은 입지가 줄고, "일반 코드로 짜고 엔진이 영속화" 패러다임이 주류가 됐다.
2. **개발자 우선**. Inngest·Trigger.dev·Hatchet의 부상은 DX(developer experience)가 결정적 차별점이 됐음을 보여준다.
3. **AI 에이전트 결합**. LangGraph·Claude·OpenAI Agents SDK가 모두 내구성 실행 백엔드 필요성에 닿고 있다.
4. **운영 단순성 경쟁**. Restate·DBOS·Hatchet은 모두 "Temporal보다 운영 쉽다"를 핵심 어필로 삼는다.
5. **클라우드 매니지드 성숙**. Temporal Cloud, Inngest Cloud, Restate Cloud, Trigger.dev Cloud — 자체 운영을 피할 수 있는 선택지가 다양해졌다.
처음 도입하는 팀에게 권하는 흐름은 이렇다.
1. 가장 골치 아픈 비동기 비즈니스 프로세스 한 개를 고른다(보통은 결제 또는 온보딩).
2. Temporal Cloud 또는 Inngest로 매니지드로 시작한다.
3. 워크플로우 정의를 코드로 짜고, 액티비티는 작고 멱등하게 유지한다.
4. 사가 + 멱등성 키 + 보상을 명시적으로 설계한다.
5. 운영 가시성(워크플로우 상태, 재시도, 데드 레터)을 확인한다.
워크플로우 엔진은 "더 많은 인프라"가 아니라 "**비즈니스 로직을 더 잘 표현할 수 있는 새 추상**"이다. 잘 쓰면, 분산 시스템의 가장 까다로운 부분이 "그냥 코드"가 된다.
참고 자료
1. [Temporal — Open Source Durable Execution Platform](https://temporal.io/)
2. [Temporal Cloud Documentation](https://docs.temporal.io/cloud)
3. [Temporal Server 1.25 Release Notes](https://github.com/temporalio/temporal/releases)
4. [Cadence Workflow — Uber Open Source](https://cadenceworkflow.io/)
5. [Restate — Distributed Application Toolkit](https://restate.dev/)
6. [Hatchet — Postgres-backed Workflow Engine](https://hatchet.run/)
7. [Inngest — Reliable Background Jobs and Workflows](https://www.inngest.com/)
8. [Trigger.dev v3 — Open Source Background Jobs](https://trigger.dev/)
9. [DBOS — Database-Backed Durable Programs](https://www.dbos.dev/)
10. [Dapr Workflows Documentation](https://docs.dapr.io/developing-applications/building-blocks/workflow/)
11. [AWS Step Functions Documentation](https://docs.aws.amazon.com/step-functions/)
12. [Azure Durable Functions Overview](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-overview)
13. [Google Cloud Workflows](https://cloud.google.com/workflows)
14. [Cloudflare Workflows Documentation](https://developers.cloudflare.com/workflows/)
15. [Conductor / Orkes](https://orkes.io/)
16. [Camunda 8 Documentation](https://docs.camunda.io/)
17. [Apache Airflow](https://airflow.apache.org/)
18. [Dagster](https://dagster.io/)
19. [Prefect](https://www.prefect.io/)
20. [Argo Workflows](https://argoproj.github.io/workflows/)
21. [Saga Pattern — microservices.io](https://microservices.io/patterns/data/saga.html)
22. [Outbox Pattern — microservices.io](https://microservices.io/patterns/data/transactional-outbox.html)
23. [Stripe API — Idempotency](https://docs.stripe.com/api/idempotent_requests)
24. [LangGraph Documentation](https://langchain-ai.github.io/langgraph/)
25. [Anthropic Claude Agent SDK](https://docs.anthropic.com/en/docs/agents)
26. [OpenAI Agents SDK](https://github.com/openai/openai-agents-python)
27. [Maxim Fateev — Designing Temporal (QCon)](https://www.infoq.com/presentations/temporal-design/)
28. [Mercari Engineering Blog — Microservices](https://engineering.mercari.com/en/)
현재 단락 (1/556)
2026년 어느 회사의 결제 시스템 회의.