AWS Lambda Durable Functions を使ってみた ─ ステートフルなワークフローをコードだけで書ける時代へ
はじめに
私自身、実務でStep Functionsのようなワークフローサービスを使ったことはないのですが、複雑なワークフローを作る際にこういった少しヘビーなサービス?を使うのに抵抗がある方、多いんじゃないかなと思います。
そんな悩みを解決してくれるのが、re:Invent 2025で発表された AWS Lambda Durable Functions です。簡単に言うと、Lambdaのコードの中に直接ワークフローのロジックを書ける機能で、ステート管理や自動リトライを別サービスなしに実現できます!
この記事では、Lambdaの基本はわかっている方を対象に、Durable Functionsの概念と、コンソールから作るシンプルなデモをご紹介します。
Lambda Durable Functions とは?
通常のLambdaの限界
通常のLambdaは「1回呼ばれたら完結する」処理に向いています。しかし、次のような要件になると途端に複雑になります。
- 複数のAPIを順番に呼び出して、それぞれの結果を使いたい
- 処理の途中でエラーが起きたら、途中から再開したい
- 人の承認待ちなど、長時間待機が必要な処理を作りたい
従来はStep Functionsで解決していましたが、Durable Functionsを使えばLambdaのコード内に直接書けるようになりました。
Durable Functionsの3つの特徴
| 特徴 | 内容 |
|---|---|
| 自動チェックポイント | 各ステップ完了後に進捗を自動保存。途中から再開できる |
| 長時間実行対応 | 最長1年まで実行を一時停止可能。待機中は課金なし |
| 障害耐性 | ステップ単位で自動リトライ。冪等性を保ちながら再実行 |
ハンズオン: シンプルなワークフローをコンソールから作ってみる
ここからは実際にコンソールを操作してみます。作るのは3ステップの注文処理ワークフローです。
前提条件
- AWSアカウントがある
- 東京リージョン(ap-northeast-1)または対応リージョンを使用
対応リージョンについて: 2026年4月時点で東京リージョン(ap-northeast-1)での展開状況は公式ページで確認してください。
Step 1: Lambda関数を作成する
AWSマネジメントコンソールにログインし、Lambdaのページを開きます。
「関数の作成」をクリック
「一から作成」を選び、以下の設定を入力します。
| 項目 | 値 |
|---|---|
| 関数名 | sample-order-workflow-durable |
| ランタイム | Python 3.14 |
また、カスタム設定から「永続実行」のトグルを有効にしたうえで、下記を設定します。
| 設定項目 | 推奨値 |
|---|---|
| 実行タイムアウト | 1分(デモ用) |
| 保持期間 | 1日(デモ用) |
Durable実行タイムアウトと通常タイムアウトの違い: 通常タイムアウトは1回の実行の上限、Durable実行タイムアウトはワークフロー全体(待機時間を含む)の上限です。
これで関数を作成します。
Step 2: コードを書く
コードエディタに以下を貼り付けます。
なお、今回はAWSブログの記事を参考にしており、ソースコードも同じものを使って動きを試してみました。
https://aws.amazon.com/jp/blogs/news/build-multi-step-applications-and-ai-workflows-with-aws-lambda-durable-functions/
import aws_lambda_durable as durable
import time
import random
# ── 個別のステップ関数 ──────────────────────────
import random
from aws_durable_execution_sdk_python import (
DurableContext,
StepContext,
durable_execution,
durable_step,
)
from aws_durable_execution_sdk_python.config import (
Duration,
StepConfig,
CallbackConfig,
)
from aws_durable_execution_sdk_python.retries import (
RetryStrategyConfig,
create_retry_strategy,
)
@durable_step
def validate_order(step_context: StepContext, order_id: str) -> dict:
"""Validates order data using AI."""
step_context.logger.info(f"Validating order: {order_id}")
# 本番稼働: Amazon Bedrock を呼び出して注文の完全性と正確性を検証
return {"order_id": order_id, "status": "validated"}
@durable_step
def send_for_approval(step_context: StepContext, callback_id: str, order_id: str) -> dict:
"""Sends order for approval using the provided callback token."""
step_context.logger.info(f"Sending order {order_id} for approval with callback_id: {callback_id}")
# 本番稼働: callback_id を外部承認システムに送信
# 外部システムは Lambda SendDurableExecutionCallbackSuccess を呼び出すか
# 承認が完了したらこの callback_id を使って SendDurableExecutionCallbackFailure API を送信
return {
"order_id": order_id,
"callback_id": callback_id,
"status": "sent_for_approval"
}
@durable_step
def process_order(step_context: StepContext, order_id: str) -> dict:
"""Processes the order with retry logic for transient failures."""
step_context.logger.info(f"Processing order: {order_id}")
# 時々失敗する不安定な API をシミュレート
if random.random() > 0.4:
step_context.logger.info("Processing failed, will retry")
raise Exception("Processing failed")
return {
"order_id": order_id,
"status": "processed",
"timestamp": "2025-11-27T10:00:00Z",
}
@durable_execution
def lambda_handler(event: dict, context: DurableContext) -> dict:
try:
order_id = event.get("order_id")
# ステップ 1: 注文を検証
validated = context.step(validate_order(order_id))
if validated["status"] != "validated":
raise Exception("Validation failed") # ターミナルエラー - 実行を停止
context.logger.info(f"Order validated: {validated}")
# ステップ 2: コールバックを作成
callback = context.create_callback(
name="awaiting-approval",
config=CallbackConfig(timeout=Duration.from_minutes(3))
)
context.logger.info(f"Created callback with id: {callback.callback_id}")
# ステップ 3: callback_id を使用して承認リクエストを送信
approval_request = context.step(send_for_approval(callback.callback_id, order_id))
context.logger.info(f"Approval request sent: {approval_request}")
# ステップ 4: コールバックの結果を待つ
# これは、外部システムが SendDurableExecutionCallbackSuccess または SendDurableExecutionCallbackFailure を呼び出すまでブロックされる
approval_result = callback.result()
context.logger.info(f"Approval received: {approval_result}")
# ステップ 5: カスタム再試行戦略による注文を処理
retry_config = RetryStrategyConfig(max_attempts=3, backoff_rate=2.0)
processed = context.step(
process_order(order_id),
config=StepConfig(retry_strategy=create_retry_strategy(retry_config)),
)
if processed["status"] != "processed":
raise Exception("Processing failed") # ターミナルエラー
context.logger.info(f"Order successfully processed: {processed}")
return processed
except Exception as error:
context.logger.error(f"Error processing order: {error}")
raise error # 再発生して実行を失敗させる
「Deploy」ボタンをクリックしてデプロイします。
Step 3: テストイベントを作成して実行する
「テスト」タブから、以下のJSONを入力してテストを実行します。
{
"order_id": "ORD-2026-0501"
}
「テスト」ボタンを押すと実行が始まります。
Step 4: Durable実行の状態を確認する
実行が完了したら、「永続実行」タブを開いてみましょう。ここがDurable Functionsの醍醐味です。
実行IDをクリックすると、各ステップの詳細が確認できます。
| ステップ | 状態 | 実行時間 |
|---|---|---|
| validate_order | ✅ 成功 | 274ms |
| send_for_approval | ✅ 成功 | 600ms |
| process_order |
|
1分(タイムアウト設定時間) |
それぞれのステップがチェックポイントとして記録されているのがわかります。
process_orderはシミュレータされた不安定なAPIが原因で処理が止まり、さらにコールバックリトライを3分に設定していたため、エラー発生時に1分のタイムアウトエラーが発生しました。
こういった形で各プロセスを繋げる形でワークフローを組み、各ステップごとのステータスもLambda関数の画面で確認することができました。
ユースケース:こんな場面で使いたい
個人的に「これは使えそう」と感じたユースケースをいくつか挙げます。
1. ECサイトの注文処理
在庫確認 → 決済 → 配送手配 → 通知、という一連の流れで途中のどのステップでエラーが起きても安全に再試行できます。
2. AI/MLパイプライン
データ前処理 → モデル推論(時間がかかる)→ 結果保存 のような処理で、推論が失敗しても前処理からやり直さずに済みます。
3. AIエージェントのワークフロー処理
ワークフロー型のAIエージェントを作る際に、Step Functionsなどに頼らずLambdaで完結して構築することができそうです!
Step Functions との使い分け
「Step Functionsはどうなるの?」という疑問が湧くと思います。以下の通りになるかなと。
| Lambda Durable Functions | Step Functions | |
|---|---|---|
| 向いているケース | コード中心のフロー、開発速度重視 | 複雑な分岐・並列・エラーハンドリング、視覚的な管理 |
| 定義方法 | コードに直接書く | ASL(JSON/YAML) |
| 可視化 | Durable実行タブ(シンプル) | ワークフロービジュアライザ(リッチ) |
| 複雑さ | シンプルなフローに最適 | 複雑なオーケストレーションに強い |
シンプルな直線的フローや「Step Functionsを使うほどでもないけど確実性は欲しい」というケースにDurable Functionsは非常にハマると感じました。
まとめ
AWS Lambda Durable Functionsを使うと、
- ✅ ステートフルなワークフローをLambdaコードだけで書ける
- ✅ 自動チェックポイントで途中からの再試行が可能
- ✅ 最長1年の待機(待機中は無課金)
- ✅ コンソールのDurable実行タブで状態を可視化できる
個人的には「Step Functionsを使うのが大げさに感じていたケース」の多くがDurable Functionsで解決できそうです!
今回はサンプルコードを使って軽く動きを見てみただけではありますので、どこかで本格的に何か作ってみたいなと思いました。
皆さんもぜひ試してみてください!




