Lambda Durable Functions: 1년 동안 실행되는 워크플로우 구축
I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line unchanged and preserve all formatting, markdown, and technical terms as requested.
우리가 모두 무시해 온 문제
다단계 워크플로우를 만든 마지막 순간을 생각해 보세요:
- 결제 확인을 기다리는 주문 처리 시스템.
- 인간 검토 단계가 포함된 콘텐츠 검토 파이프라인.
- 하루 종일 사용자가 업로드한 파일을 처리하는 데이터 파이프라인.
아마 Step Functions를 사용했을 겁니다, 그렇죠? 저도 그랬어요—청구서를 보기 전까지는.
Step Functions는 상태 전환당 요금을 부과합니다.
$25 per million transitions sounds cheap, but a six‑state approval workflow costs you every single time it runs, even while it’s just waiting for someone to click “Approve” in an email.
💡 기다림의 실제 비용
| 워크플로우 | 실행당 전환 수 | 월 실행 횟수 | 월 비용 |
|---|---|---|---|
| Approval (8 transitions) | 8 | 10 000 | $2.00 |
대기 외에 아무 작업도 하지 않는 상태에 대해 비용을 지불하고 있습니다. Lambda Durable Functions? 대기 시간은 $0.00입니다.
Lambda Durable Functions란 무엇인가?
Lambda Durable Functions를 사용하면 일반 코드—JSON 상태 머신 없이—로 장기 실행 워크플로를 작성할 수 있습니다. 일반 TypeScript 또는 Python 코드를 작성하면 AWS가 다음을 처리합니다:
- 오케스트레이션
- 상태 지속성
- 일시 중지 후 재개
핵심은 await 문에 있습니다. 함수가 내구성 작업을 await 하면 AWS는:
- 함수의 상태를 체크포인트합니다.
- 종료합니다.
- 작업이 완료되면(5초 후든 5개월 후든) 복원합니다.
대기 시간에 대한 비용은 발생하지 않습니다.
Lambda Durable Functions 작동 방식
flowchart TD
A[Function Starts] --> B[Execute Code]
B --> C{Await Durable Task?}
C -- Yes --> D[Checkpoint State]
D --> E[Suspend Function]
E --> F[Wait for Event/Timer]
F --> G[Restore State]
G --> H[Resume Execution]
C -- No --> I[Continue]
I --> H
(간단한 텍스트 다이어그램을 원하시면 아래를 보세요.)
Function Starts → Execute Code → Await Durable Task?
↓ ↓
Continue Checkpoint State
↓ ↓
Complete/Next Step Suspend Function
↓
Wait for Event/Timer
↓
Restore State
↓
Resume Execution
실제 예시: 문서 승인 워크플로우
아래는 실용적인 문서 승인 시스템으로,
- 여러 검토자를 기다립니다.
- 알림을 보냅니다.
- 아무도 응답하지 않으면 에스컬레이션합니다.
Step Functions에서는 복잡한 선택 로직을 가진 15개 이상의 상태가 필요하지만, Durable Functions에서는 단순히 코드 몇 줄이면 됩니다.
import { DurableOrchestration } from '@aws-lambda/durable-functions';
export const documentApprovalWorkflow = new DurableOrchestration(
async (context) => {
const { documentId, reviewers } = context.input;
// 1️⃣ Send notification to all reviewers
await context.callActivity('sendReviewNotifications', {
documentId,
reviewers,
});
// 2️⃣ Wait for approvals with timeout (7 days)
const approvalTask = context.waitForEvent('approval', 7 * 24 * 60 * 60);
const reminderTask = context.createTimer(3 * 24 * 60 * 60); // 3 days
const winner = await Promise.race([approvalTask, reminderTask]);
if (winner === 'reminder') {
// Send reminder and wait again
await context.callActivity('sendReminderEmails', { reviewers });
const secondApproval = await context.waitForEvent('approval', 4 * 24 * 60 * 60);
if (!secondApproval) {
// Escalate to manager
await context.callActivity('escalateToManager', { documentId });
await context.waitForEvent('managerApproval', 2 * 24 * 60 * 60);
}
}
// 3️⃣ Process approval
const result = await context.callActivity('processApproval', {
documentId,
approvedAt: new Date().toISOString(),
});
return result;
}
);
// External system triggers approval
export const submitApproval = async (workflowId: string, decision: string) => {
await durableClient.raiseEvent(workflowId, 'approval', { decision });
};
핵심 요점: 이 코드는 동료에게 설명하듯이 스크립트처럼 읽힙니다—JSON도 없고
$.decision == 'approved'같은 조건도 없으며, 순수한 프로그래밍 로직만 사용됩니다.
다단계 애플리케이션: 최적의 지점
Durable Functions는 여러 개의 개별 단계가 각각 서로 다른 시간(초에서 시간까지) 동안 실행될 때 빛을 발합니다. 아래 패턴들은 매우 효과적으로 작동합니다.
1️⃣ 데이터 파이프라인 패턴
파일 업로드를 받고, 여러 변환을 거쳐 처리한 뒤, 품질 검사를 기다리고, 최종 결과를 게시합니다. 각 단계는 파일 크기에 따라 몇 초에서 몇 시간까지 걸릴 수 있습니다.

2️⃣ 인간 개입 패턴
이 경우 Durable Functions는 Step Functions을 압도적으로 능가합니다. 인간의 결정을 기다려야 할 때—승인, 콘텐츠 검토, 수동 데이터 입력 등—Durable Functions는 다음을 가능하게 합니다:
- 비용을 발생시키지 않고 실행을 일시 중지합니다.
- 자동으로 알림이나 에스컬레이션을 보냅니다.
- 인간이 행동을 취하면 정확히 중단된 지점부터 재개합니다.
3️⃣ 예약 배치 패턴
하루 동안 데이터를 청크 단위로 처리하고, 결과를 집계하며, 보고서를 생성합니다. 전통적인 cron 작업은 실행 간 상태를 유지하지 못합니다. Durable Functions는 이를 유지합니다.
export const dailyReportWorkflow = new DurableOrchestration(
async (context) => {
const results = [];
// Process batches every 6 hours
for (let i = 0; i < 4; i++) {
const batchResult = await context.callActivity('processBatch', {
batchNumber: i,
timestamp: new Date()
});
results.push(batchResult);
// Wait 6 hours before next batch
if (i < 3) {
await context.createTimer(6 * 60 * 60);
}
}
// Generate final report with all batches
return await context.callActivity('generateReport', { results });
}
);
Lambda Durable Functions vs. Step Functions: 솔직한 비교
| Factor | Lambda Durable Functions | Step Functions (Standard) |
|---|---|---|
| Max Duration | 365일 | 365일 |
| Waiting Cost | $0 (상태가 지속되고 함수가 일시 중단됨) | 월 4,000회 전환 이후 무료 |
| Execution Cost | Lambda 가격 ($0.20 per 1 M 요청) | $25 per 1 M 상태 전환 |
| State Machine | 코드 기반 (TypeScript/Python) | JSON ASL (Amazon States Language) |
| Versioning | 코드 배포에 내장 | 수동 버전 관리 |
| Testing | 표준 단위 테스트, 로컬 디버깅 | Step Functions Local 또는 AWS 필요 |
| Visual Editor | 없음 (코드 전용) | Workflow Studio (드래그 앤 드롭) |
| Error Handling | try‑catch 블록 | JSON 내 재시도 정책 |
비용 분류 예시
시나리오: 승인 워크플로우가 8단계이며, 사람의 응답을 평균 48 시간 동안 기다리고, 월 50 000개의 문서를 처리합니다.
Step Functions 비용
- 50 000 워크플로우 × 8 상태 전이 = 400 000 전이
- (400 000 – 4 000 무료 티어) × $0.000025 = $9.90 / month
Durable Functions 비용
- 50 000 워크플로우 × 3 Lambda 호출 (시작, 재개, 완료) = 150 000 요청
- 150 000 × $0.0000002 = $0.03 / month
절감액: 99.7 % (대기 시간이 긴 워크플로우의 경우).
Durable Functions를 사용하면 안 되는 경우
Durable Functions도 훌륭하지만, Step Functions가 더 나은 경우가 있습니다:
- 시각적 워크플로 편집기가 필요할 때 – 비기술적인 이해관계자들이 Step Functions의 Workflow Studio를 선호합니다.
- 대규모 병렬 처리 – Step Functions의 Map 상태는 10 000+ 병렬 브랜치를 우아하게 처리합니다.
- AWS 서비스 통합 – Step Functions는 220+ 직접 통합을 제공하지만, Durable Functions는 맞춤 코드를 작성해야 합니다.
- 컴플라이언스 요구사항 – 시각적인 감사 추적을 Step Functions의 실행 기록으로 더 쉽게 생성할 수 있습니다.
시작하기: 첫 번째 Durable Function
AWS SAM 템플릿 사용
sam init --runtime nodejs20.x --app-template durable-function
cd my-durable-app
sam build && sam deploy --guided
또는 CDK로 배포
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as durable from '@aws-cdk/aws-lambda-durable-functions';
export class DurableStack extends cdk.Stack {
constructor(scope: cdk.App, id: string) {
super(scope, id);
const workflow = new durable.DurableFunction(this, 'MyWorkflow', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('functions/workflow'),
timeout: cdk.Duration.minutes(15),
maxDuration: cdk.Duration.days(365)
});
}
}
배운 교훈을 통한 모범 사례
- 활동을 멱등성(idempotent)으로 설계하세요. AWS는 실패 후 활동을 재시도할 수 있으므로, 중복 호출을 정상적으로 처리하도록 설계합니다.
- 워크플로우 상태에 큰 데이터를 저장하지 마세요. 상태 제한은 256 KB이며, 큰 페이로드는 S3에 저장하고 참조만 전달합니다.
- 상관 관계 ID를 사용하세요. 외부 시스템이 워크플로우에 신호를 보낼 때, 무작위 UUID 대신 의미 있는 실행 ID(예:
order-{orderId})를 제공하십시오. - 현실적인 타임아웃을 설정하세요. 워크플로우는 1년까지 실행될 수 있지만, 개별 활동은 훨씬 짧은 타임아웃(초에서 분 단위)으로 제한해야 합니다.
- CloudWatch로 모니터링하세요. 멈춘 워크플로우, 실패한 활동, 예상치 못한 대기 시간에 대한 알람을 설정합니다.

결론
Lambda Durable Functions는 서버리스 오케스트레이션의 중요한 진화를 나타냅니다. 이 기능을 통해 다음을 얻을 수 있습니다:
- 단순성 – 워크플로를 코드로 작성합니다.
- 비용 절감 – 대기 중에는 비용이 청구되지 않습니다.
- 강력함 – 워크플로를 최대 1년까지 실행할 수 있습니다.
새로운 장기 실행 워크플로를 구축하고 있다면—특히 사람의 개입 단계가 있거나 대기 시간이 긴 경우—Durable Functions부터 시작하세요. 코드를 적게 작성하고, 비용을 적게 지불하며, 검증된 AWS 인프라에서 워크플로가 실행된다는 사실에 안심하고 더 잘 잘 수 있습니다.
기존 Step Functions에 대해… 워크플로가 대부분 대기 시간이라면 마이그레이션을 고려하세요. 복잡한 분기 로직과 AWS 서비스 통합이 많은 빠르게 움직이는 워크플로의 경우, Step Functions가 여전히 최선의 선택일 수 있습니다.
서버리스 세계가 훨씬 더 흥미로워졌습니다. 이제 1년 동안 실행되는 무언가를 만들 때입니다. 🚀
Durable Functions의 혜택을 받을 수 있는 워크플로는 무엇인가요? 아래에 댓글을 남겨 주시고 함께 이야기해요!