- Published on
내구성 워크플로우 엔진 2026 완벽 가이드 - Temporal · Restate · Hatchet · Inngest · Trigger.dev · Cadence · DBOS · Dapr Workflows 심층 분석
- Authors

- Name
- Youngju Kim
- @fjvbn20031
프롤로그 — "백그라운드 잡인가, 워크플로우인가?"
2026년 어느 회사의 결제 시스템 회의.
주니어: "결제 후 메일 보내는 건 그냥 큐에 넣고 워커가 처리하면 되죠?" 시니어: "그 워커가 죽으면?" 주니어: "재시도하면 되잖아요." 시니어: "근데 메일은 이미 두 번 갔다면? 환불은 했는데 재고는 안 풀렸다면? 결제는 됐는데 주문 상태는 pending에 멈춰 있다면?" 주니어: "..." 시니어: "그게 워크플로우 엔진이 필요한 순간이야."
이 짧은 대화에 2026년 분산 시스템의 핵심 고민이 담겨 있다. Cron + Celery + Redis로 시작한 백그라운드 잡이, 결제·주문·구독·온보딩·AI 에이전트라는 다단계 비동기 비즈니스 프로세스로 진화하면서, 단순 큐로는 감당이 안 되는 영역이 생겼다.
내구성 실행(durable execution) — 코드를 짜듯이 워크플로우를 쓰지만, 그 코드의 모든 단계가 영속화돼서 프로세스가 죽었다 깨어나도 정확히 같은 자리에서 이어진다. 2026년 이 패러다임은 Temporal이 만든 카테고리에서 Restate·Hatchet·Inngest·Trigger.dev v3·DBOS가 각자의 답을 내놓는 풍성한 시장으로 변했다.
이 글은 그 전체 지형을 정리한다. 무엇이 내구성 실행인지부터, 각 엔진의 설계 철학, 코드 예제, Saga·Outbox 같은 패턴, AI 에이전트 오케스트레이션에서의 위치, 그리고 한국·일본 빅테크가 무엇을 어떻게 쓰는지까지.
1장 · 내구성 실행이란 무엇인가 — 이벤트 소싱과 리플레이
Durable execution의 한 줄 정의는 "함수의 모든 입출력과 비결정적 부분을 이벤트 로그에 영속화하고, 장애 후 재시작 시 로그를 리플레이해 정확히 같은 상태로 복구하는 실행 모델"이다.
이 아이디어의 뿌리는 세 가지에 있다.
- 이벤트 소싱(event sourcing) — 상태를 직접 저장하지 않고, 상태를 만든 사건들을 저장한다.
- 결정적 리플레이(deterministic replay) — 같은 이벤트 로그에 같은 코드를 돌리면 항상 같은 결과가 나와야 한다.
- 사이드 이펙트 격리 — 외부 호출(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
import { proxyActivities, sleep, defineSignal, setHandler } from '@temporalio/workflow'
import type * as activities from '../activities'
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
import { Worker } from '@temporalio/worker'
import * as activities from './activities'
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 예시.
import * as restate from '@restatedev/restate-sdk'
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 예시.
import { inngest } from './client'
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 우선.
예시.
import { task, wait } from '@trigger.dev/sdk/v3'
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 예시.
import * as df from 'durable-functions'
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 위에서 동작하는 내구성 워크플로우라는 점.
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from '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에서 사가.
import { proxyActivities } from '@temporalio/workflow'
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 예시.
import { proxyActivities } from '@temporalio/workflow'
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년 워크플로우 엔진의 큰 흐름.
- 코드 중심으로 통일. JSON/YAML/BPMN DSL은 입지가 줄고, "일반 코드로 짜고 엔진이 영속화" 패러다임이 주류가 됐다.
- 개발자 우선. Inngest·Trigger.dev·Hatchet의 부상은 DX(developer experience)가 결정적 차별점이 됐음을 보여준다.
- AI 에이전트 결합. LangGraph·Claude·OpenAI Agents SDK가 모두 내구성 실행 백엔드 필요성에 닿고 있다.
- 운영 단순성 경쟁. Restate·DBOS·Hatchet은 모두 "Temporal보다 운영 쉽다"를 핵심 어필로 삼는다.
- 클라우드 매니지드 성숙. Temporal Cloud, Inngest Cloud, Restate Cloud, Trigger.dev Cloud — 자체 운영을 피할 수 있는 선택지가 다양해졌다.
처음 도입하는 팀에게 권하는 흐름은 이렇다.
- 가장 골치 아픈 비동기 비즈니스 프로세스 한 개를 고른다(보통은 결제 또는 온보딩).
- Temporal Cloud 또는 Inngest로 매니지드로 시작한다.
- 워크플로우 정의를 코드로 짜고, 액티비티는 작고 멱등하게 유지한다.
- 사가 + 멱등성 키 + 보상을 명시적으로 설계한다.
- 운영 가시성(워크플로우 상태, 재시도, 데드 레터)을 확인한다.
워크플로우 엔진은 "더 많은 인프라"가 아니라 "비즈니스 로직을 더 잘 표현할 수 있는 새 추상"이다. 잘 쓰면, 분산 시스템의 가장 까다로운 부분이 "그냥 코드"가 된다.
참고 자료
- Temporal — Open Source Durable Execution Platform
- Temporal Cloud Documentation
- Temporal Server 1.25 Release Notes
- Cadence Workflow — Uber Open Source
- Restate — Distributed Application Toolkit
- Hatchet — Postgres-backed Workflow Engine
- Inngest — Reliable Background Jobs and Workflows
- Trigger.dev v3 — Open Source Background Jobs
- DBOS — Database-Backed Durable Programs
- Dapr Workflows Documentation
- AWS Step Functions Documentation
- Azure Durable Functions Overview
- Google Cloud Workflows
- Cloudflare Workflows Documentation
- Conductor / Orkes
- Camunda 8 Documentation
- Apache Airflow
- Dagster
- Prefect
- Argo Workflows
- Saga Pattern — microservices.io
- Outbox Pattern — microservices.io
- Stripe API — Idempotency
- LangGraph Documentation
- Anthropic Claude Agent SDK
- OpenAI Agents SDK
- Maxim Fateev — Designing Temporal (QCon)
- Mercari Engineering Blog — Microservices