re:Invent 2025 会場からコップンカー!!
アプリケーションサービス部の千葉です。
2025年12月、AWS は Lambda Durable Functions を一般公開しました。
この新機能により、Lambda 関数内で複数ステップのワークフローを構築し、最長1年間の待機も可能になります。
「Step Functions があるのに、なぜ新しいワークフロー機能が必要なのか?」
この疑問に答えながら、Durable Functions の特徴、適切なユースケース、そして Step Functions との使い分けについて解説します。
Durable Functions とは
基本コンセプト: Durable Functions は、通常の Lambda 関数にチェックポイント機能を追加したものです。
# NOTE: # Durable Functions は Durable Execution SDK で Lambda のハンドラを wrap し、 # ハンドラ内で DurableContext(step / wait / parallel 等のAPI)を利用します。 # SDK の import パスやラッパー関数名は更新される可能性があるため、 # 最新の名称は公式ドキュメント/SDKに合わせてください。 async def handler(event, lambda_context, durable_context): # Step 1: 注文を受け付け order = await durable_context.step("create_order", create_order, event) # Step 2: 決済処理 payment = await durable_context.step("process_payment", charge_card, order) # Step 3: 承認待ち(最長48時間) approval = await durable_context.wait_for_callback( "manager_approval", timeout_hours=48, ) # Step 4: 配送手配 shipment = await durable_context.step("arrange_shipment", ship_order, order) return {"status": "completed", "shipment_id": shipment.id}
各 step や wait の完了時に自動的にチェックポイントが作成され、障害発生時はそこから再開できます。
# 主な特徴
| 特徴 | 説明 |
|---|---|
| 自動チェックポイント | 各ステップ完了時に進捗を永続化 |
| コスト効率の良い待機 | Wait により実行をサスペンドでき、待機中は実行コンピュートの消費を抑えられる |
| 最長1年の待機 | 人間の判断を含む長期プロセスに対応 |
| 慣れ親しんだ開発体験 | 通常の Lambda コードと同じ書き方 |
Step Functions との比較: 開発体験の違い
# Durable Functions: コードベース
## 条件分岐も通常のPythonで記述 if order.total > 100000: approval = await context.wait_for_callback("executive_approval") else: approval = await context.step("auto_approve", auto_approve, order)
# Step Functions: 定義ファイルベース
States: CheckAmount: Type: Choice Choices: - Variable: "$.order.total" NumericGreaterThan: 100000 Next: ExecutiveApproval Default: AutoApprove ExecutiveApproval: Type: Task Resource: arn:aws:states:::lambda:invoke.waitForTaskToken
機能比較
| 観点 | Durable Functions | Step Functions |
|---|---|---|
| 定義方法 | コード内で直接記述 | ASL (JSON/YAML) |
| 学習コスト | 低(Lambda 経験者向け) | 中〜高(ASL 習得必要) |
| 可視化 | コンソールで実行履歴確認 | ビジュアルワークフローエディタ |
| デバッグ | 通常の Lambda と同様 | Workflow Studio で視覚的に |
| 並列実行 | context.parallel() / context.map() | Parallel / Map ステート |
| エラーハンドリング | try-except で記述 | Catch/Retry を定義 |
| 実行状態 | RUNNING / SUCCEEDED / FAILED など | より詳細な状態遷移 |
| 最大実行時間 | 1年 | Standard: 1年 / Express: 5分 |
| 料金体系 | 実行時間課金(Wait により実行コンピュートを抑えられる)、回数課金 | 状態遷移回数課金 |
ユースケース: Durable Functions が適しているケース
1. シンプルな承認フロー
申請 → 承認待ち → 処理実行 → 完了
直線的なフローで、コードで書いた方が早いケース。
2. 既存 Lambda の拡張
すでに Lambda で実装されているロジックに、待機やリトライを追加したい場合。
Step Functions への移行コストを避けられます。
3. 人間の判断を含む AI ワークフロー
# AI が下書き → 人間がレビュー → AI が修正 → 公開
draft = await context.step("ai_draft", generate_with_llm, prompt)
feedback = await context.wait_for_callback("human_review", timeout_days=7)
final = await context.step("ai_revise", revise_with_llm, draft, feedback)
await context.step("publish", publish_content, final)
LLM を使ったコンテンツ生成で、人間のレビューを待機するパターン。
4. 分散トランザクション(Saga パターン)
try:
payment = await context.step("charge", charge_card, order)
inventory = await context.step("reserve", reserve_inventory, order)
shipment = await context.step("ship", create_shipment, order)
except Exception as e:
# 補償トランザクション
await context.step("rollback", compensate, order)
raise
複数サービスにまたがる処理を、コードで直感的に記述。
ユースケース: Step Functions が適しているケース
1. 複雑な並列・分岐処理
10以上の分岐、複数の並列実行、動的な並列度制御が必要な場合は、ビジュアルエディタで設計した方が見通しが良い。
2. 運用監視が重要なミッションクリティカルな処理
Step Functions の成熟した監視・アラート機能が活きるケース。
3. 非エンジニアもワークフローを理解する必要がある
ビジネスサイドのステークホルダーにフローを説明する際、ビジュアル図があると効果的。
4. AWS サービスとのネイティブ統合
# Step Functions は200以上のAWSサービスと直接統合 Resource: arn:aws:states:::dynamodb:putItem
Lambda を経由せず直接 AWS サービスを呼び出せるため、シンプルな統合では Step Functions の方が効率的。
定期バッチ処理との相性
Durable Functions を検討する際、定期バッチ処理との相性には注意が必要です。
問題の起きそうなシナリオ
Day 1: バッチ実行開始 → 外部API待ち(Wait状態)
Day 2: 新しいバッチが起動 → Day 1 の Wait がまだ残っている
→ データ不整合の可能性
なぜ問題になるか
- Wait を含む実行は、運用上 RUNNING として見える場合がある
- バッチの二重起動を避けるには、RUNNING の有無確認に加え、ExecutionName の命名規則や開始時刻などで「対象実行」を絞る設計が必要
- 「前回と同一系統の実行が残っていない」ことを確認せずに次のバッチが走ると、データ不整合の可能性がある
対策
import boto3 def has_running_executions(function_name: str) -> bool: """RUNNING 状態の実行が存在するかを確認(ページネーション対応)""" client = boto3.client("lambda") token = None while True: kwargs = {"FunctionName": function_name, "Status": "RUNNING"} if token: kwargs["NextToken"] = token response = client.list_durable_executions_by_function(**kwargs) executions = response.get("Executions", []) if executions: return True # 1件でも見つかったら即終了 token = response.get("NextToken") if not token: return False def batch_entry(event, context): if has_running_executions("my-durable-function"): raise Exception("前回の実行が完了していません") # 本処理を開始
本質的な考え方
Durable Functions はイベントドリブンな処理を想定しています:
- ユーザーアクションで開始
- 人間の判断や外部イベントを待機
- 完了まで一貫したフロー
定期バッチのような「前回と今回が独立している」処理では、実行の重複管理を自前で実装する必要があります。
まとめ:選択のフローチャート
ワークフローを実装したい
│
├─ 既存の Lambda コードを拡張したい?
│ └─ Yes → Durable Functions
│
├─ ビジュアルでの設計・監視が重要?
│ └─ Yes → Step Functions
│
├─ AWS サービスと直接統合したい?
│ └─ Yes → Step Functions
│
├─ 人間の待機を含む直線的フロー?
│ └─ Yes → Durable Functions
│
├─ 複雑な並列・分岐がある?
│ └─ Yes → Step Functions
│
└─ 迷ったら → Step Functions(実績と成熟度)
おわりに
Lambda Durable Functions は、シンプルなワークフローを「Lambda らしく」書きたい開発者にとって魅力的な選択肢です。
一方で、GA 直後ということもあり、運用ノウハウはこれから蓄積されていく段階です。本番導入の際は、監視・アラートの設計と、実行状態の管理方法を 十分に検討することをおすすめします。
参考リンク
- https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html
- https://aws.amazon.com/blogs/aws/build-multi-step-applications-and-ai-workflows-with-aws-lambda-durable-functions/
- https://docs.aws.amazon.com/lambda/latest/dg/durable-examples.html