下記公式記事を見て実装
開発者はイベントハンドラーで「Steps」や「Waits」などのdurable operationsを使用して、進捗をチェックポイントし、料金を発生させることなく、待機期間中に実行を一時停止します。
簡単に言うと、Lambdaを途中で待ち状態にして、15分しばり&料金の発生を回避することができる。Step Functionsを書かずに、Lambdaコード内で長時間・複数step・callback待ちのワークフローが実装できる。生成AIの領域だと、human-in-the-loopやレスポンスの長いLLM等のAPI処理が入るシナリオに対応できる。
実装
Python版は下記SDKを使用する必要がある
pip install aws-durable-execution-sdk-python
aws configure sso
aws sso login --profile
sam build
sam deploy --guided
aws sts get-caller-identity
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Python Lambda Durable Functions onboarding sample
Globals:
Function:
Runtime: python3.14
Timeout: 30
MemorySize: 512
CodeUri: src/
Resources:
DurableOnboardingFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: durable-onboarding-python
Handler: onboarding_handler.handler
AutoPublishAlias: live
DurableConfig:
ExecutionTimeout: 86400 # 24 hours
RetentionPeriodInDays: 7
Environment:
Variables:
CALLBACK_BASE_URL: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}"
Policies:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy
# 本番では DynamoDB / SES など必要分だけ追加
CallbackFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: durable-onboarding-callback
Handler: callback_handler.handler
Events:
VerifyApi:
Type: HttpApi
Properties:
Path: /verify
Method: GET
Policies:
- Statement:
- Effect: Allow
Action:
- lambda:SendDurableExecutionCallbackSuccess
Resource: "*"
# 本番では対象の Durable Function に絞る
Outputs:
DurableOnboardingAliasArn:
Value: !Ref DurableOnboardingFunction.Alias
CallbackUrl:
Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/verify"
aws lambda invoke ` --function-name "arn:aws:lambda:ap-northeast-1:*********:function:durable-onboarding-python:live" ` --invocation-type Event ` --cli-binary-format raw-in-base64-out ` --payload '{\"user_id\":\"user-001\",\"email\":\"user@example.com\",\"name\":\"User1\"}' ` response.json
下記コードは、ユーザー登録後にメール認証を待ち、認証リンクがクリックされたらユーザーを有効化する Lambda Durable Functions のサンプルです。
1. オンボーディング本体 Lambda
- Durable Function
- 入力検証
- ユーザープロファイル作成
- メール認証 callback 待ち
- ユーザー有効化
- Welcomeメール送信
2. メール認証 callback Lambda
- 通常の Lambda
- Function URL または API Gateway から呼ばれる
- callbackId を受け取り、Durable Function に認証成功を返す
import os
from typing import Any
from aws_durable_execution_sdk_python import (
DurableContext,
StepContext,
durable_execution,
durable_step,
)
from aws_durable_execution_sdk_python.config import Duration, WaitForCallbackConfig
from aws_durable_execution_sdk_python.types import WaitForCallbackContext
CALLBACK_BASE_URL = os.environ["CALLBACK_BASE_URL"]
@durable_step
def validate_input(step_context: StepContext, event: dict) -> dict:
email = event.get("email")
name = event.get("name")
user_id = event.get("user_id")
if not email or not name or not user_id:
raise ValueError("email, name, user_id are required")
return {
"user_id": user_id,
"email": email,
"name": name,
}
@durable_step
def create_user_profile(step_context: StepContext, user: dict) -> dict:
"""
本番では DynamoDB などに保存する。
注意: Durable Step はリトライされる可能性があるので、
user_id を idempotency key にして二重作成を防ぐ。
"""
step_context.logger.info(
"Creating user profile",
extra={"user_id": user["user_id"], "email": user["email"]},
)
# 例:
# dynamodb.put_item(
# TableName="Users",
# Item=...,
# ConditionExpression="attribute_not_exists(user_id)"
# )
return {
**user,
"status": "PENDING_EMAIL_VERIFICATION",
}
@durable_step
def activate_user(step_context: StepContext, user_id: str) -> dict:
"""
本番では DynamoDB の status を ACTIVE に更新する。
"""
step_context.logger.info("Activating user", extra={"user_id": user_id})
return {
"user_id": user_id,
"status": "ACTIVE",
}
@durable_step
def send_welcome_email(step_context: StepContext, email: str) -> dict:
"""
本番では SES / SendGrid / Mailgun などで送信する。
"""
step_context.logger.info("Sending welcome email", extra={"email": email})
return {"sent": True}
@durable_execution
def handler(event: dict, context: DurableContext) -> dict:
context.logger.info("Start onboarding")
user = context.step(
validate_input(event),
name="validate-input",
)
profile = context.step(
create_user_profile(user),
name="create-user-profile",
)
def submit_verification_email(
callback_id: str,
callback_context: WaitForCallbackContext,
) -> None:
verification_url = (
f"{CALLBACK_BASE_URL}/verify"
f"?callbackId={callback_id}"
f"&userId={profile['user_id']}"
)
# 本番では callback_id をログにそのまま出さない方が安全。
callback_context.logger.info(
"Sending verification email",
extra={"email": profile["email"], "user_id": profile["user_id"]},
)
# 例: SESでメール送信
# ses.send_email(
# Source="no-reply@example.com",
# Destination={"ToAddresses": [profile["email"]]},
# Message={
# "Subject": {"Data": "Please verify your email"},
# "Body": {"Text": {"Data": f"Click: {verification_url}"}},
# },
# )
print(f"[DEV ONLY] verification_url={verification_url}")
verification_result = context.wait_for_callback(
submitter=submit_verification_email,
name="wait-for-email-verification",
config=WaitForCallbackConfig(
timeout=Duration.from_hours(24),
heartbeat_timeout=Duration.from_minutes(30),
),
)
if not isinstance(verification_result, dict) or not verification_result.get("verified"):
return {
"status": "EMAIL_VERIFICATION_FAILED",
"user_id": profile["user_id"],
"verification_result": verification_result,
}
activated = context.step(
activate_user(profile["user_id"]),
name="activate-user",
)
context.step(
send_welcome_email(profile["email"]),
name="send-welcome-email",
)
return {
"status": "COMPLETED",
"user": activated,
}
Durable Function本体に対して、メール認証リンクをクリックされた時にcallbackを返すLambda
=> 待っているDurable Functionを再開させる係
import json
import boto3
lambda_client = boto3.client("lambda")
def handler(event, context):
params = event.get("queryStringParameters") or {}
callback_id = params.get("callbackId")
user_id = params.get("userId")
if not callback_id:
return {
"statusCode": 400,
"body": "callbackId is required",
}
result = {
"verified": True,
"user_id": user_id,
}
lambda_client.send_durable_execution_callback_success(
CallbackId=callback_id,
Result=json.dumps(result).encode("utf-8"),
)
return {
"statusCode": 200,
"headers": {"Content-Type": "text/html; charset=utf-8"},
"body": "<h1>Email verified</h1><p>You can close this page.</p>",
}
動作
Lambda関数の実行後、メールに認証URLが送信されるので、それをクリックするとメール認証が成功する。
※サンプルコードではメール送信の関数がコメントアウトされているので、CWからURLを確認。
ユーザー登録開始
|
v
[Durable Function本体]
|
| 1. validate-input
| 2. create-user-profile
| 3. 認証メール送信
| 4. wait-for-email-verification で一時停止
v
ユーザーがメール認証リンクをクリック
|
v
[Callback受付Lambda]
|
| send_durable_execution_callback_success
v
[Durable Function本体が再開]
|
| 5. activate-user
| 6. send-welcome-email
v
オンボーディング完了

