

# Lambda の耐久性のある関数
<a name="durable-functions"></a>

Lambda の耐久性のある関数により、中断しても信頼性の高い進行状況を維持しながら、最大 1 年間実行できる回復力のある複数ステップのアプリケーションおよび AI ワークフローを構築できます。耐久性のある関数が実行されると、この完全なライフサイクルは耐久性のある実行と呼ばれ、チェックポイントを使用して進行状況が追跡され、再生を通じて障害から自動的に復旧し、完了した作業をスキップしながら最初から再実行されます。

各関数内では、耐久性のあるオペレーションを基礎的な構成要素として使用します。ステップでは、組み込みの再試行および進行状況の追跡機能でビジネスロジックが実行されますが、待機はコンピューティング料金を発生させずに実行が停止されます。ヒューマンインザループのワークフローや外部依存関係のポーリングなど、長時間のプロセスに最適です。注文の処理、マイクロサービスの調整、エージェンティック AI アプリケーションのオーケストレーションを問わず、ユーザーが使い慣れたプログラミング言語でコードを記述している間に、耐久性のある関数は状態を自動的に維持し、障害から復旧します。

## 主な利点
<a name="durable-functions-benefits"></a>

**回復力のあるコードを自然に記述:** 使い慣れたプログラミングコンストラクトを使用して、障害を自動的に処理するコードを記述します。組み込みチェックポイント、透過的な再試行、自動復旧により、ビジネスロジックが明確で焦点を合わせた状態が維持されます。

**使用した分のみ支払う:** 待機オペレーション中、関数はコンピューティング料金を発生せずに停止します。数時間または数日間待機する長時間のワークフローでは、アイドル待機ではなく、実際の処理時間に対してのみ料金が発生します。

**運用の単純性:** Lambda のサーバーレスモデルを使用すると、インフラストラクチャを管理せず、ゼロへのスケーリングを含む自動スケーリングを実現できます。耐久性のある関数は状態管理、再試行ロジック、障害復旧を自動的に処理し、運用上のオーバーヘッドを削減します。

## 耐久性のある関数を使用するタイミング
<a name="durable-functions-use-cases"></a>

**短期間の調整:** 障害時の自動ロールバックにより、複数のサービス間で支払い、インベントリ、配送を調整します。完了の保証により、検証、支払い承認、インベントリ割り当て、履行を通じて注文を処理します

**自信を持って支払いを処理する:** 障害中にトランザクション状態を維持し、再試行を自動的に処理する回復力のある支払いフローを構築します。複数ステップの認可、不正チェック、決済を支払いプロバイダー間で調整し、ステップ間で完全な監査可能性を実現します。

**信頼性の高い AI ワークフローの構築:** モデル呼び出しを連鎖し、人間のフィードバックを取り入れ、障害発生時に長時間実行されるタスクを決定的に処理する複数ステップの AI ワークフローを作成します。停止後に自動的に再開し、アクティブな実行時間に対してのみ支払います。

**複雑な注文履行の調整:** 組み込みレジリエンスでインベントリ、支払い、配送、通知システム間の注文処理を調整します。部分的な障害を自動的に処理し、中断しても順序の状態を維持し、コンピューティングリソースを消費せずに外部イベントを効率的に待機します。

**複数ステップのビジネスワークフローの自動化:** 数日または数週間に及ぶ従業員のオンボーディング、ローン承認、コンプライアンスプロセスの信頼性の高いワークフローを構築します。プロセスのステータスや履歴を完全に可視化しながら、人間による承認、システム統合、スケジュールされたタスクの全体でワークフロー状態を維持します。

### 耐久性のある関数と Step Functions の比較
<a name="durable-functions-vs-step-functions"></a>

耐久性の高い関数と Step Functions はどちらも、自動状態管理によるワークフローオーケストレーションを提供します。主な違いは、実行される場所とワークフローの定義方法です。
+ **耐久性のある関数:** Lambda 内で実行、標準プログラミング言語を使用、Lambda 環境内で管理
+ **Step Functions:** スタンドアロンサービス、グラフベースの DSL またはビジュアルデザイナー、メンテナンス不要でフルマネージド

耐久性のある関数は、ワークフローがビジネスロジックと緊密に連携している Lambda でのアプリケーション開発に最適です。Step Functions は、ビジュアルデザイン、220 以上のサービスへのネイティブ統合、メンテナンス不要のインフラストラクチャを必要とする AWS サービス間のワークフローオーケストレーションに優れています。

詳細な比較については、「[耐久性のある関数か Step Functions か](durable-step-functions.md)」を参照してください。

## 仕組み
<a name="durable-functions-how-it-works"></a>

 内部では、耐久性のある関数はチェックポイントや再生メカニズムを使用する通常の Lambda 関数であり、ユーザー定義の停止ポイント (耐久性のある実行と一般的に呼ばれる) を通じて進行状況を追跡し、長時間のオペレーションをサポートします。関数が一時停止または中断から再開されると、システムによって再生が実行されます。再生中、コードは最初から実行されますが、完了したオペレーションを再実行せずに、保存された結果を使用して完了したチェックポイントをスキップします。この再生メカニズムにより、長時間実行を有効にしながら一貫性を確保できます。

このチェックポイントと再生メカニズムをアプリケーションで活用するため、Lambda は耐久性のある実行 SDK を提供します。SDK によってチェックポイントおよび再生の管理による複雑さが抽象化され、コードで使用する耐久性のあるオペレーションと呼ばれる単純なプリミティブが公開されます。SDKはJavaScript、TypeScript、Python、Java（プレビュー）に対応しており、既存の Lambda 開発ワークフローとシームレスに統合できます。

SDK を使用すると Lambda イベントハンドラーをラップし、イベントと並行して DurableContext が提供されます。このコンテキストにより、ステップや待機などの耐久性のあるオペレーションにアクセスできます。関数ロジックは通常のシーケンシャルコードとして記述しますが、サービスを直接呼び出さずに、これらの呼び出しを自動チェックポイントおよび再試行のステップでラップします。実行を一時停止する必要がある場合、料金を発生させずに関数を停止する待機を追加します。SDK によって複雑な状態管理および再生がすべて内部で処理されるため、コードはクリーンで読みやすい状態が維持されます。

 ![\[Filter for Amazon Inspector results related to Lambda functions\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/how_durable_works.png) 

## 次のステップ
<a name="durable-functions-next-steps"></a>
+ [耐久性のある関数の開始方法](durable-getting-started.md)
+ [耐久性のある実行 SDK を見る](durable-execution-sdk.md)
+ [耐久性のある関数か Step Functions か](durable-step-functions.md)
+ [耐久性のある関数のモニタリングとデバッグ](durable-monitoring.md)
+ [セキュリティとアクセス許可の確認](durable-security.md)
+ [ベストプラクティスに従う](durable-best-practices.md)

# 基本概念
<a name="durable-basic-concepts"></a>

Lambda は、JavaScript、TypeScript、Python に耐久性のある実行 SDK を提供します。これらの SDK は耐久性のある関数を構築するための基盤であり、進行状況のチェックポイント、再試行の処理、実行フローの管理に必要なプリミティブが提供されます。SDK の完全なドキュメントや例については、GitHub の「[JavaScript/TypeScript SDK](https://github.com/aws/aws-durable-execution-sdk-js)」および「[Python SDK](https://github.com/aws/aws-durable-execution-sdk-python)」を参照してください。

## 耐久性のある実行
<a name="durable-execution-concept"></a>

**耐久性のある実行**は Lambda の耐久性のある関数における完全なライフサイクルを表し、チェックポイントおよび再生メカニズムを使用してビジネスロジックの進行状況を追跡し、実行を停止し、障害から復旧します。関数が停止または中断の後に再開すると、以前に完了したチェックポイントが再生されて、関数は実行を続行します。

ライフサイクルには、実行を完了するために Lambda 関数の複数の呼び出しが含まれる場合があります (特に停止または障害復旧の後)。このアプローチにより、中断しても信頼性の高い進行状況を維持しながら、関数を長期間 (最大 1 年) 実行できるようになります。

**再生の仕組み**  
関数の実行時に、Lambda はすべての耐久性のあるオペレーション (ステップ、待機、その他のオペレーション) の実行ログを保持します。関数を一時停止する必要がある場合、または中断が発生した場合、Lambda によってこのチェックポイントログが保存されて実行が停止されます。再開すると、Lambda は最初から関数を再度呼び出し、チェックポイントログを再生し、保存された値を完了したオペレーションに置き換えます。つまり、コードが再度実行されますが、以前に完了したステップは再実行されません。代わりに保存された結果が使用されます。

この再生メカニズムは、耐久性のある関数を理解するために不可欠です。コードは再生中に決定的である必要があります。つまり、同じ入力で同じ結果が生成されます。副作用 (ランダムな数値の生成や現在の時刻の取得など) を伴う操作は、再生中に異なる値を生成し、非決定的な動作を引き起こす可能性があるため、ステップ外では避けてください。

## DurableContext
<a name="durable-context-concept"></a>

**DurableContext** は、耐久性のある関数が受け取るコンテキストオブジェクトです。チェックポイントを作成して実行フローを管理するステップや待機など、耐久性のあるオペレーションの方法を提供します。

耐久性のある関数は、デフォルトの Lambda コンテキストではなく、`DurableContext` を受け取ります。

------
#### [ TypeScript ]

```
import {
  DurableContext,
  withDurableExecution,
} from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const result = await context.step(async () => {
      return "step completed";
    });
    return result;
  },
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import (
    DurableContext,
    durable_execution,
    durable_step,
)

@durable_step
def my_step(step_context, data):
    # Your business logic
    return result

@durable_execution
def handler(event, context: DurableContext):
    result = context.step(my_step(event["data"]))
    return result
```

------

耐久性のある関数用 Python SDK によって同期メソッドが使用され、`await` はサポートされません。TypeScript SDK では `async/await` が使用されます。

## Steps
<a name="steps-concept"></a>

**ステップ**は、組み込みの再試行および自動チェックポイントでビジネスロジックを実行します。各ステップは結果を保存し、中断後に完了したステップから関数を再開できるようにします。

------
#### [ TypeScript ]

```
// Each step is automatically checkpointed
const order = await context.step(async () => processOrder(event));
const payment = await context.step(async () => processPayment(order));
const result = await context.step(async () => completeOrder(payment));
```

------
#### [ Python ]

```
# Each step is automatically checkpointed
order = context.step(lambda: process_order(event))
payment = context.step(lambda: process_payment(order))
result = context.step(lambda: complete_order(payment))
```

------

## 待機状態
<a name="wait-states-concept"></a>

**待機状態**は、継続する時間になるまで関数の実行が停止する (さらに課金を停止する) 計画された一時停止です。使用して期間、外部コールバック、特定の条件を待機します。

------
#### [ TypeScript ]

```
// Wait for 1 hour without consuming resources
await context.wait({ seconds:3600 });

// Wait for external callback
const approval = await context.waitForCallback(
  async (callbackId) => sendApprovalRequest(callbackId)
);
```

------
#### [ Python ]

```
# Wait for 1 hour without consuming resources
context.wait(3600)

# Wait for external callback
approval = context.wait_for_callback(
    lambda callback_id: send_approval_request(callback_id)
)
```

------

関数で待機が発生した場合、または一時停止する必要がある場合、Lambda はチェックポイントログを保存して実行を停止します。再開する際、Lambda は関数を再度呼び出してチェックポイントログを再生し、保存された値を完了したオペレーションに置き換えます。

もっと複雑なワークフローの場合、耐久性のある Lambda 関数には高度なオペレーションも用意されています。これには、同時実行に `parallel()`、配列の処理に `map()`、ネストされたオペレーションに `runInChildContext()`、ポーリングに `waitForCondition()` などがあります。各オペレーションを使用するタイミングに関する詳細な例およびガイダンスについては、「[例](durable-examples.md)」を参照してください。

## 他の関数の呼び出し
<a name="invoke-concept"></a>

**呼び出し**により、耐久性のある関数は他の Lambda 関数を呼び出して結果を待機できます。呼び出し元の関数は呼び出される関数の実行中に停止し、結果を保持するチェックポイントが作成されます。特殊な関数が特定のタスクを処理するモジュラーワークフローを構築できるようになります。

`context.invoke()` を使用して耐久性のある関数内から他の関数を呼び出します。呼び出しはチェックポイントされるため、呼び出される関数が完了した後に関数が中断された場合、関数を再呼び出しせずに、保存された結果で再開されます。

------
#### [ TypeScript ]

```
// Invoke another function and wait for result
const customerData = await context.invoke(
  'validate-customer',
  'arn:aws:lambda:us-east-1:123456789012:function:customer-service:1',
  { customerId: event.customerId }
);

// Use the result in subsequent steps
const order = await context.step(async () => {
  return processOrder(customerData);
});
```

------
#### [ Python ]

```
# Invoke another function and wait for result
customer_data = context.invoke(
    'arn:aws:lambda:us-east-1:123456789012:function:customer-service:1',
    {'customerId': event['customerId']},
    name='validate-customer'
)

# Use the result in subsequent steps
order = context.step(
    lambda: process_order(customer_data),
    name='process-order'
)
```

------

呼び出される関数は、耐久性のある Lambda 関数または標準の Lambda 関数のいずれかの場合があります。耐久性のある関数を呼び出した場合、呼び出し元の関数は完全な耐久性のある実行が完了するまで待機します。このパターンは各関数が特定のドメインを処理するマイクロサービスアーキテクチャで一般的であり、特殊で再利用可能な関数で複雑なワークフローを作成できます。

**注記**  
クロスアカウントの呼び出しはサポートされていません。呼び出される関数は、呼び出し元の関数と同じ AWS アカウントに存在する必要があります。

## 耐久性のある関数の設定
<a name="durable-configuration-basic"></a>

耐久性のある関数には、実行動作およびデータ保持を制御する特定の構成設定があります。これらの設定は標準の Lambda 関数設定とは別で、耐久性のある実行ライフサイクルの全体に適用されます。

**DurableConfig** オブジェクトは、耐久性のある関数の設定を定義します。

```
{
  "ExecutionTimeout": Integer,
  "RetentionPeriodInDays": Integer
}
```

### 実行タイムアウト
<a name="durable-execution-timeout"></a>

**実行タイムアウト**は、耐久性のある実行を開始から完了まで実行できる期間を制御します。単一の関数の呼び出しが実行可能な時間を制御する Lambda 関数のタイムアウトとは異なります。

耐久性のある実行はチェックポイント、待機、再生を進行しながら、複数の Lambda 関数の呼び出しをまたくことがあります。実行タイムアウトは、個々の関数の呼び出しではなく、耐久性のある実行の合計経過時間に適用されます。

**違いを理解する**  
Lambda 関数のタイムアウト (最大 15 分) は、関数の個々の呼び出しを制限します。耐久性のある実行タイムアウト (最大 1 年) は、実行の開始から完了、障害発生、タイムアウトまでの合計時間を制限します。この期間中、関数がステップを処理し、待機し、障害から復旧するとき、複数回呼び出されることがあります。

例えば、耐久性のある実行タイムアウトを 24 時間に設定して、Lambda 関数タイムアウトを 5 分に設定した場合、次の条件が該当します。
+ 各関数の呼び出しは 5 分以内に完了する必要があります
+ 耐久性のある実行全体は最大 24 時間実行できます
+ この 24 時間の期間中に関数を何度も呼び出すことができます
+ 待機オペレーションは Lambda 関数のタイムアウトにはカウントされませんが、実行タイムアウトにはカウントされます。

Lambda コンソール、AWS CLI、AWS SAM を使用して、耐久性のある関数を作成するときに実行タイムアウトを設定できます。Lambda コンソールで関数を選択したら [設定] を選択し、耐久性のある実行を選択します。実行タイムアウト値を秒単位で設定します (デフォルトで 86400 秒/24 時間、最小 60 秒、最大 31536000 秒/1 年)。

**注記**  
実行タイムアウトおよび Lambda 関数タイムアウトは設定が異なります。Lambda 関数のタイムアウトは、個々の呼び出しを実行できる時間を制御します (最大 15 分)。実行タイムアウトは、耐久性のある実行全体の合計経過時間を制御します (最大 1 年)。

### 保持期間
<a name="durable-retention-period"></a>

**保持期間**は、耐久性のある実行が完了した後に Lambda が実行履歴およびチェックポイントデータを保持する期間を制御します。このデータにはステップ結果、実行状態、完全なチェックポイントログが含まれます。

保持期間が終了したら、Lambda は実行履歴およびチェックポイントデータを削除します。実行の詳細を取得したり、実行を再生したりすることはできなくなりました。保持期間は、実行が終了状態 (SUCCEEDED、FAILED、STOPPED、TIMED\$1OUT) に達したときに開始されます。

Lambda コンソール、AWS CLI、AWS SAM を使用して、耐久性のある関数を作成するときに保持期間を設定できます。Lambda コンソールで関数を選択したら [設定] を選択し、耐久性のある実行を選択します。保持期間の値を日数単位で設定します (デフォルトで 14 日、最小 1 日、最大 90 日)。

コンプライアンス要件、デバッグのニーズ、コストに関する考慮事項に基づいて、保持期間を選択してください。保持期間を長くすると、デバッグや監査の増加する時間に対応できますが、ストレージコストが増加します。

## 関連情報
<a name="durable-basic-concepts-see-also"></a>
+ [耐久性のある関数か Step Functions か](durable-step-functions.md) – 耐久性のある関数と Step Functions を比較して、各アプローチがどのような場合に最も効果的かを明らかにします。

# Lambda の耐久性のある関数を作成する
<a name="durable-getting-started"></a>

Lambda の耐久性のある関数の使用を開始するには、Lambda コンソールを使用して耐久性のある関数を作成します。数分で、ステップを使用してチェックポイントベースの実行のデモンストレーションを待機する耐久性のある関数を作成してデプロイできます。

チュートリアルを実行すると、`DurableContext` オブジェクトの使用方法、ステップを含むチェックポイントの作成、待機で実行の一時停止など、基礎的な耐久性のある関数の概念について学習します。待機後に関数が再開されると、再生が機能する方法についても説明します。

分かりやすくするため、関数の作成には Python または Node.js ランタイムを使用します。これらはインタープリター言語なので、コンソールの組み込みコードエディタで関数のコードを直接編集できます。

Java 版の耐久性のある関数は現在プレビュー中のため、デプロイにはコンテナイメージを使用する必要があります。コンテナイメージから耐久性のある関数を作成する方法の詳細については、「[耐久関数のサポートされているランタイム](durable-supported-runtimes.md)」または「[コードとしてのインフレストラクチャを使用して Lambda の耐久性のある関数をデプロイする](durable-getting-started-iac.md)」を参照してください。

**注記**  
耐久性のある関数は現在、Python および Node.js (JavaScript/TypeScript) ランタイムと、Java などのコンテナイメージ (OCI) をサポートしています。サポートされているランタイムバージョンとコンテナイメージオプションの詳細なリストについては、「[耐久関数のサポートされているランタイム](durable-supported-runtimes.md)」を参照してください。Lambda によるコンテナイメージの使用に関する詳細については、「Lambda デベロッパーガイド」の「[コンテナイメージを使用した Lambda 関数の作成](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html)」を参照してください。

**ヒント**  
**サーバーレスソリューション**を構築する方法については、「[サーバーレスデベロッパーガイド](https://docs.aws.amazon.com/serverless/latest/devguide/)」を参照してください。

## 前提条件
<a name="durable-getting-started-prerequisites"></a>

### AWS アカウント にサインアップする
<a name="sign-up-for-aws"></a>

AWS アカウント がない場合は、以下のステップを実行して作成します。

**AWS アカウント にサインアップするには**

1. [https://portal.aws.amazon.com/billing/signup](https://portal.aws.amazon.com/billing/signup) を開きます。

1. オンラインの手順に従います。

   サインアップ手順の一環として、電話またはテキストメッセージを受け取り、電話キーパッドで検証コードを入力します。

   AWS アカウントにサインアップすると、*AWS アカウントのルートユーザー*が作成されます。ルートユーザーには、アカウントのすべての AWS のサービス とリソースへのアクセス権があります。セキュリティのベストプラクティスとして、ユーザーに管理アクセスを割り当て、ルートユーザーのみを使用して[ルートユーザーアクセスが必要なタスク](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html#root-user-tasks)を実行してください。

サインアップ処理が完了すると、AWS からユーザーに確認メールが送信されます。[https://aws.amazon.com/](https://aws.amazon.com/) の **[マイアカウント]** をクリックして、いつでもアカウントの現在のアクティビティを表示し、アカウントを管理することができます。

### 管理アクセスを持つユーザーを作成する
<a name="create-an-admin"></a>

AWS アカウントにサインアップしたら、AWS アカウントのルートユーザーをセキュリティで保護し、AWS IAM アイデンティティセンター を有効にして、管理ユーザーを作成します。これにより、日常的なタスクにルートユーザーを使用しないようにします。

**AWS アカウントのルートユーザー をセキュリティで保護する**

1.  **[ルートユーザー]** を選択し、AWS アカウント のメールアドレスを入力して、アカウント所有者として [AWS マネジメントコンソール](https://console.aws.amazon.com/) にサインインします。次のページでパスワードを入力します。

   ルートユーザーを使用してサインインする方法については、「*AWS サインイン ユーザーガイド*」の「[ルートユーザーとしてサインインする](https://docs.aws.amazon.com/signin/latest/userguide/console-sign-in-tutorials.html#introduction-to-root-user-sign-in-tutorial)」を参照してください。

1. ルートユーザーの多要素認証 (MFA) を有効にします。

   手順については、「*IAM ユーザーガイド*」の「[AWS アカウント ルートユーザーの仮想 MFA デバイスを有効にする (コンソール)](https://docs.aws.amazon.com/IAM/latest/UserGuide/enable-virt-mfa-for-root.html)」を参照してください。

**管理アクセスを持つユーザーを作成する**

1. IAM アイデンティティセンターを有効にします。

   手順については、「*AWS IAM アイデンティティセンター ユーザーガイド*」の「[AWS IAM アイデンティティセンター の有効化](https://docs.aws.amazon.com//singlesignon/latest/userguide/get-set-up-for-idc.html)」を参照してください。

1. IAM アイデンティティセンターで、ユーザーに管理アクセスを付与します。

   IAM アイデンティティセンターディレクトリ をアイデンティティソースとして使用するチュートリアルについては、「*AWS IAM アイデンティティセンター ユーザーガイド*」の「[デフォルトの IAM アイデンティティセンターディレクトリ を使用してユーザーアクセスを設定する](https://docs.aws.amazon.com//singlesignon/latest/userguide/quick-start-default-idc.html)」を参照してください。

**管理アクセス権を持つユーザーとしてサインインする**
+ IAM アイデンティティセンターのユーザーとしてサインインするには、IAM アイデンティティセンターのユーザーの作成時に E メールアドレスに送信されたサインイン URL を使用します。

  IAM アイデンティティセンターユーザーを使用してサインインする方法については、「*AWS サインイン ユーザーガイド*」の「[AWS アクセスポータルにサインインする](https://docs.aws.amazon.com/signin/latest/userguide/iam-id-center-sign-in-tutorial.html)」を参照してください。

**追加のユーザーにアクセス権を割り当てる**

1. IAM アイデンティティセンターで、最小特権のアクセス許可を適用するというベストプラクティスに従ったアクセス許可セットを作成します。

   手順については、「*AWS IAM アイデンティティセンター ユーザーガイド*」の「[アクセス許可セットを作成する](https://docs.aws.amazon.com//singlesignon/latest/userguide/get-started-create-a-permission-set.html)」を参照してください。

1. グループにユーザーを割り当て、そのグループにシングルサインオンアクセス権を割り当てます。

   手順については、「*AWS IAM アイデンティティセンター ユーザーガイド*」の「[グループを追加する](https://docs.aws.amazon.com//singlesignon/latest/userguide/addgroups.html)」を参照してください。

## コンソールで Lambda の耐久性のある関数を作成します
<a name="getting-started-create-durable-function"></a>

この例では、耐久性のある関数は自動チェックポイントを使用して、複数のステップで注文を処理します。関数によって注文 ID を含む JSON オブジェクトを受け取り、注文が検証され、支払いが処理され、注文が確認されます。各ステップは自動的にチェックポイントされるため、関数が中断された場合、最後に完了したステップから再開されます。

関数では待機オペレーションも示され、外部確認の待機をシミュレーションするため、実行が短時間一時停止されます。

**コンソールで耐久性のある関数を作成する方法**

1. Lambda コンソールの [[関数]](https://console.aws.amazon.com/lambda/home#/functions) ページを開きます。

1. [**関数の作成**] を選択してください。

1. **[一から作成]** を選択します。

1. **[基本情報]** ペインで、**[関数名]** に「`myDurableFunction`」を入力します。

1. **[ランタイム]** で、**[Node.js 24]** または **[Python 3.14]** のいずれかを選択します。

1. **[耐久性のある実行の有効化]** を選択します。

Lambda によってチェックポイントオペレーション (`lambda:CheckpointDurableExecutions` および `lambda:GetDurableExecutionState`) のアクセス許可を含む[実行ロール](lambda-intro-execution-role.md)が使用され、耐久性のある関数が作成されます。

**注記**  
Lambda ランタイムには Durable Execution SDK が含まれているため、依存関係をパッケージ化せず、耐久性のある関数をテストできます。ただし、本番稼働用のデプロイパッケージに SDK を含めることをお勧めします。バージョン整合性が確保され、関数に影響を与える可能性があるランタイム更新を回避できます。

コンソールの組み込み Code Editor を使用して、耐久性のある関数コードを追加します。

------
#### [ Node.js ]

**コンソールでコードを変更するには**

1. **[コード]** タブを選択します。

   Lambda が関数コードを作成すると、それがコンソールの組み込みコードエディタに表示されます。コードエディターに **index.mjs** タブが表示されない場合は、次の図に示すように、ファイルエクスプローラーで **index.mjs** を選択します。  
![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/durable-nodejs.png)

1. 次のコードを **index.mjs** タブに貼り付け、Lambda が作成したコードを置き換えます。

   ```
   import {
     DurableContext,
     withDurableExecution,
   } from "@aws/durable-execution-sdk-js";
   
   export const handler = withDurableExecution(
     async (event, context) => {
       const orderId = event.orderId;
       
       // Step 1: Validate order
       const validationResult = await context.step(async (stepContext) => {
         stepContext.logger.info(`Validating order ${orderId}`);
         return { orderId, status: "validated" };
       });
       
       // Step 2: Process payment
       const paymentResult = await context.step(async (stepContext) => {
         stepContext.logger.info(`Processing payment for order ${orderId}`);
         return { orderId, status: "paid", amount: 99.99 };
       });
       
       // Wait for 10 seconds to simulate external confirmation
       await context.wait({ seconds: 10 });
       
       // Step 3: Confirm order
       const confirmationResult = await context.step(async (stepContext) => {
         stepContext.logger.info(`Confirming order ${orderId}`);
         return { orderId, status: "confirmed" };
       });
           
       return {
         orderId: orderId,
         status: "completed",
         steps: [validationResult, paymentResult, confirmationResult]
       };
     }
   );
   ```

1. **[DEPLOY]** セクションで、**[デプロイ]** を選択して関数のコードを更新します。  
![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

**耐久性のある関数コードの概要**  
次のステップに進む前に、関数コードについて紹介し、耐久性のある関数の主な概念について説明します。
+ `withDurableExecution` ラッパー

  耐久性のある関数は `withDurableExecution` でラップされます。このラッパーによって `DurableContext` オブジェクトが提供され、チェックポイントオペレーションが管理されることで、耐久性のある実行が実現されます。
+ `DurableContext` オブジェクト

  標準の Lambda コンテキストではなく、関数は `DurableContext` を受け取ります。このオブジェクトは、チェックポイントを作成する `step()` や `wait()` などの耐久性のあるオペレーションの方法について説明します。
+ ステップとチェックポイント

  各 `context.step()` の呼び出しは、実行前と実行後にチェックポイントを作成します。関数が中断された場合、最後に完了したチェックポイントから再開されます。関数は完了したステップを再実行しません。代わりに、保存された結果を使用します。
+ 待機オペレーション

  `context.wait()` 呼び出しにより、コンピューティングリソースが消費されずに実行が一時停止されます。待機が完了すると、Lambda によって関数が再度呼び出されてチェックポイントログが再生され、保存された値が完了したステップに置き換えられます。
+ 再生メカニズム

  待機または中断後に関数が再開されると、Lambda によって最初からコードが実行されます。ただし、完了したステップは再実行されません。Lambda によってチェックポイントログの結果が再生されます。そのため、コードは決定的である必要があります。

------
#### [ Python ]

**コンソールでコードを変更するには**

1. **[コード]** タブを選択します。

   Lambda が関数コードを作成すると、それがコンソールの組み込みコードエディタに表示されます。コードエディターに **lambda\$1function.py** タブが表示されない場合は、次の図に示すように、ファイルエクスプローラーで **lambda\$1function.py** 選択します。  
![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/durable-python.png)

1. 次のコードを **lambda\$1function.py** タブに貼り付け、Lambda が作成したコードを置き換えます。

   ```
   from aws_durable_execution_sdk_python import (
       DurableContext,
       durable_execution,
       durable_step,
   )
   from aws_durable_execution_sdk_python.config import Duration
   
   @durable_step
   def validate_order(step_context, order_id):
       step_context.logger.info(f"Validating order {order_id}")
       return {"orderId": order_id, "status": "validated"}
   
   @durable_step
   def process_payment(step_context, order_id):
       step_context.logger.info(f"Processing payment for order {order_id}")
       return {"orderId": order_id, "status": "paid", "amount": 99.99}
   
   @durable_step
   def confirm_order(step_context, order_id):
       step_context.logger.info(f"Confirming order {order_id}")
       return {"orderId": order_id, "status": "confirmed"}
   
   @durable_execution
   def lambda_handler(event, context: DurableContext):
       order_id = event['orderId']
       
       # Step 1: Validate order
       validation_result = context.step(validate_order(order_id))
       
       # Step 2: Process payment
       payment_result = context.step(process_payment(order_id))
       
       # Wait for 10 seconds to simulate external confirmation
       context.wait(Duration.from_seconds(10))
       
       # Step 3: Confirm order
       confirmation_result = context.step(confirm_order(order_id))
           
       return {
           "orderId": order_id,
           "status": "completed",
           "steps": [validation_result, payment_result, confirmation_result]
       }
   ```

1. **[DEPLOY]** セクションで、**[デプロイ]** を選択して関数のコードを更新します。  
![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

**耐久性のある関数コードの概要**  
次のステップに進む前に、関数コードについて紹介し、耐久性のある関数の主な概念について説明します。
+ `@durable_execution` デコレータ

  ハンドラー関数は `@durable_execution` でデコレーションされています。このデコレータによって `DurableContext` オブジェクトが提供されてチェックポイントオペレーションが管理されることで、耐久性のある実行が実現されます。
+ `@durable_step` デコレータ

  各ステップ関数は `@durable_step` でデコレーションされています。このデコレータにより、チェックポイントを作成する耐久性のあるステップとして関数がマークされます。
+ `DurableContext` オブジェクト

  標準の Lambda コンテキストではなく、関数は `DurableContext` を受け取ります。このオブジェクトは、チェックポイントを作成する `step()` や `wait()` などの耐久性のあるオペレーションの方法について説明します。
+ ステップとチェックポイント

  各 `context.step()` の呼び出しは、実行前と実行後にチェックポイントを作成します。関数が中断された場合、最後に完了したチェックポイントから再開されます。関数は完了したステップを再実行しません。代わりに、保存された結果を使用します。
+ 待機オペレーション

  `context.wait()` 呼び出しにより、コンピューティングリソースが消費されずに実行が一時停止されます。待機が完了すると、Lambda によって関数が再度呼び出されてチェックポイントログが再生され、保存された値が完了したステップに置き換えられます。
+ Python SDK は同期します。

  Python SDK では、`await` が使用されないことに注意してください。耐久性のあるオペレーションは、すべて同期メソッドの呼び出しです。

------

## コンソールの Code Editor を使用して耐久性のある関数を呼び出す
<a name="get-started-invoke-durable-manually"></a>

明示的なバージョンが指定されていない (または公開されていない) 場合、コンソールは `$LATEST` バージョン修飾子を使用して耐久性のある関数を呼び出します。ただし、コードの確定的な実行には、常に安定したバージョンを指す修飾 ARN を使用する必要があります。

**関数のバージョンを発行する方法**

1. **[バージョニング]** タブを選択します。

1. **[新しいバージョンを発行]** を選択します。

1. **[バージョンの説明]** には、「**Initial version**」と入力します (オプション)。

1. **[公開]** を選択します。

1. Lambda によって関数のバージョン 1 が作成されます。関数 ARN の末尾に `:1` が含まれるようになり、バージョン 1 であることが示されていることに注意してください。

次に、関数に送信するテストイベントを作成します。イベントは、注文 ID を含む JSON 形式のドキュメントです。

**テストイベントを作成するには**

1. コンソールコードエディタの **[TEST EVENTS]** セクションで、**[テストイベントを作成]** を選択します。  
![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/getting-started-tutorial/test-event.png)

1. **[イベント名]** で、「**myTestEvent**」と入力します。

1. **[Event JSON]** セクションで、デフォルトの JSON を次のように置き換えます。

   ```
   {
     "orderId": "order-12345"
   }
   ```

1. **[保存]** を選択します。

**耐久性のある関数をテストして実行を表示する方法**

コンソールコードエディタの **[TEST EVENTS]** セクションで、テストイベントの横にある実行アイコンを選択します。

![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/getting-started-tutorial/run-test-event.png)


耐久性のある関数の実行が開始されます。10 秒の待機が含まれるため、最初の呼び出しはすぐに完了します。関数は待機期間後に再開されます。実行の進行状況は、**[耐久性のある実行]** タブで確認できます。

**耐久性のある関数の実行を表示する方法**

1. **[耐久性のある実行]** タブを選択します。

1. リストで実行を検索します。実行には現在のステータス (実行中、成功、失敗) が表示されます。

1. 実行 ID を選択して詳細を確認します。以下の情報が含まれます。
   + 各ステップが完了した日時が示される実行タイムライン
   + チェックポイント履歴
   + 待機期間
   + ステップの結果

CloudWatch Logs で関数のログを表示し、各ステップのコンソール出力を確認することもできます。

**CloudWatch Logs で関数の呼び出しレコードを表示するには**

1. Amazon CloudWatch コンソールの [[[Log groups (ロググループ)] ページ](https://console.aws.amazon.com/cloudwatch/home#logs:)] を開きます。

1. 関数のロググループの名前を選択します (`/aws/lambda/myDurableFunction`) 。

1. 下にスクロールし、表示したい関数呼び出しの**ログストリーム**を選択します。  
![\[\]](http://docs.aws.amazon.com/ja_jp/lambda/latest/dg/images/log-stream.png)

   関数の呼び出しごとにログエントリ (最初の実行および待機後の再生を含む) を確認してください。

**注記**  
`DurableContext` (`context.logger` や `stepContext.logger` など) からロガーを使用すると、Lambda コンソールの耐久性のある実行ビューとステップビューにもログが表示されます。これらのログのロードには時間がかかる場合があります。

## クリーンアップ
<a name="gettingstarted-durable-cleanup"></a>

耐久性のある関数のサンプルで作業が完了したら、削除します。また、関数のログを保存するロググループと、コンソールが作成した[実行ロール](lambda-intro-execution-role.md)も削除できます。

**Lambda 関数を削除するには**

1. Lambda コンソールの [[関数]](https://console.aws.amazon.com/lambda/home#/functions) ページを開きます。

1. 作成した関数を選択します。

1. **[アクション]** で、**[削除]** を選択します。

1. テキスト入力フィールドに **confirm** と入力し、**[削除]** を選択します。

**ロググループを削除するには**

1. Amazon CloudWatch コンソールの [[Log groups (ロググループ)] ページ](https://console.aws.amazon.com/cloudwatch/home#logs:)を開きます。

1. 関数のロググループ (`/aws/lambda/myDurableFunction`) を選択します。

1. [**アクション**]、[**ロググループの削除**] の順にクリックします。

1. **ロググループの削除**ダイアログボックスで、[**削除**] をクリックします。

**実行ロールを削除するには**

1. AWS Identity and Access Management (IAM) コンソールの [[Roles (ロール)] ページ](https://console.aws.amazon.com/iam/home?#/roles)を開きます。

1. 関数の実行ロールを選択します (`myDurableFunction-role-31exxmpl` など)。

1. **[削除]** を選択します。

1. **[ロールを削除]** ダイアログボックスにロール名を入力し、**[削除]** を選択します。

## その他のリソースと次のステップ
<a name="durable-getting-started-more-resources"></a>

コンソールを使用してシンプルな耐久性のある関数を作成してテストを行ったら、次の各ステップを実行してください。
+ 分散トランザクション、注文処理、人間によるレビューワークフローなど、耐久性のある関数の一般的なユースケースについて説明します。「[例](durable-examples.md)」を参照してください。
+ CloudWatch メトリクスおよび実行履歴を使用し、耐久性のある関数の実行をモニタリングする方法について説明します。「[モニタリングとデバッグ](durable-monitoring.md)」を参照してください。
+ 耐久性のある関数を同期的および非同期的に呼び出し、長時間の実行を管理する方法について説明します。「[耐久性のある関数の呼び出し](durable-invoking.md)」を参照してください。
+ 決定的コードの記述、チェックポイントサイズの管理、コストの最適化に関するベストプラクティスに従います。「[ベストプラクティス](durable-best-practices.md)」を参照してください。
+ 耐久性のある関数をローカルやクラウドでテストする方法について説明します。「[耐久性のある関数のテスト](durable-testing.md)」を参照してください。
+ 耐久性のある関数と Step Functions を比較して、各アプローチがどのような場合に最も効果的かを明らかにします。「[耐久性のある関数か Step Functions か](durable-step-functions.md)」を参照してください。

# AWS CLI を使用して Lambda の耐久性のある関数をデプロイして呼び出す
<a name="durable-getting-started-cli"></a>

AWS CLI を使用して、命令コマンドで Lambda の耐久性のある関数を作成してデプロイします。このアプローチにより、デプロイプロセスの各ステップを直接制御できます。

## 前提条件
<a name="durable-cli-prerequisites"></a>
+ AWS CLI をインストールして設定します。手順については、「[AWS CLI のインストール](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)」を参照してください。
+ 関数コードおよび耐久性のある実行 SDK でデプロイパッケージを作成します。
+ チェックポイントのアクセス許可で IAM 実行ロールを作成します。

## 実行ロールを作成する
<a name="durable-cli-create-role"></a>

基本的な Lambda 実行およびチェックポイントオペレーションのアクセス許可を持つ IAM ロールを作成します。

**実行ロールを作成するには**

1. Lambda のロール引き受けを許可する信頼ポリシードキュメントを作成します。`trust-policy.json` として保存します。

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
           "Service": "lambda.amazonaws.com"
         },
         "Action": "sts:AssumeRole"
       }
     ]
   }
   ```

1. ロールを作成します。

   ```
   aws iam create-role \
     --role-name durable-function-role \
     --assume-role-policy-document file://trust-policy.json
   ```

1. チェックポイントオペレーションと基本実行の耐久性のある実行ポリシーをアタッチします。

   ```
   aws iam attach-role-policy \
     --role-name durable-function-role \
     --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy
   ```

`AWSLambdaBasicDurableExecutionRolePolicy` 管理ポリシーには、チェックポイントオペレーション (`lambda:CheckpointDurableExecutions` および `lambda:GetDurableExecutionState`) と基本的な Lambda 実行に必要なアクセス許可が含まれています。

## 耐久性のある関数の作成します
<a name="durable-cli-create-function"></a>

`--durable-config` パラメータで耐久性のある関数を作成します。

**耐久性のある関数を作成する方法**

1. 依存関係を持つ関数コードを .zip ファイルにパッケージ化します。

   ```
   zip -r function.zip index.mjs node_modules/
   ```

1. 耐久性のある実行を有効にして関数を作成します。

   ```
   aws lambda create-function \
     --function-name myDurableFunction \
     --runtime nodejs22.x \
     --role arn:aws:iam::123456789012:role/durable-function-role \
     --handler index.handler \
     --zip-file fileb://function.zip \
     --durable-config '{"ExecutionTimeout": 3600, "RetentionPeriodInDays": 7}'
   ```

**注記**  
関数の作成時のみに、耐久性のある実行を有効にできます。既存の関数には有効にできません。

**注記**  
現在、Java (プレビュー) の耐久性のある関数は、コンテナイメージを介してのみ作成できます。コンテナイメージから耐久性のある関数を作成する方法の詳細については、「[耐久関数のサポートされているランタイム](durable-supported-runtimes.md)」を参照してください。

## バージョンの発行
<a name="durable-cli-publish-version"></a>

耐久性のある関数は `$LATEST` バージョン修飾子を使用して呼び出すことができますが、コードの確定的な実行を確保するためには、常に安定したバージョンを指す修飾 ARN を使用する必要があります。

```
aws lambda publish-version \
  --function-name myDurableFunction \
  --description "Initial version"
```

コマンドはバージョン ARN を返します。ARN の末尾にあるバージョン番号 (例えば、`:1`) を書き留めてください。

オプションとして、バージョンを指すエイリアスを作成します。

```
aws lambda create-alias \
  --function-name myDurableFunction \
  --name prod \
  --function-version 1
```

## 耐久性のある関数を呼び出す
<a name="durable-cli-invoke"></a>

修飾 ARN (バージョンまたはエイリアス) を使用して、耐久性のある関数を呼び出します。

**注記**  
**べき等呼び出し:** 失敗した呼び出しを再試行するときに、at-most-once の実行セマンティクスを保証する実行名を指定すると、実行が重複しないようにできます。詳細については、「[べき等性](durable-execution-idempotency.md)」を参照してください。

**同期呼び出し**  
15 分以内に完了する実行には、同期呼び出しを使用します。

```
aws lambda invoke \
  --function-name myDurableFunction:1 \
  --payload '{"orderId": "order-12345"}' \
  --cli-binary-format raw-in-base64-out \
  response.json
```

または、エイリアスを使用します。

```
aws lambda invoke \
  --function-name myDurableFunction:prod \
  --payload '{"orderId": "order-12345"}' \
  --cli-binary-format raw-in-base64-out \
  response.json
```

**非同期呼び出し**  
長時間の実行には、非同期呼び出しを使用します。

```
aws lambda invoke \
  --function-name myDurableFunction:prod \
  --invocation-type Event \
  --payload '{"orderId": "order-12345"}' \
  --cli-binary-format raw-in-base64-out \
  response.json
```

非同期呼び出しを使用すると、Lambda は即時に返します。関数はバックグラウンドで実行を続行します。

**注記**  
コンソールでのプロトタイプ作成とテストに `$LATEST` を使用できます。本番稼働ワークロードの場合は、公開されたバージョンまたはエイリアスを使用します。

## 耐久性のある実行を管理する
<a name="durable-cli-manage-executions"></a>

次のコマンドを使用して、耐久性のある関数の実行を管理してモニタリングします。

**実行を一覧表示する**  
耐久性のある関数におけるすべての実行を一覧表示します。

```
aws lambda list-durable-executions-by-function \
  --function-name myDurableFunction
```

**実行の詳細を取得する**  
特定の実行に関する詳細を取得します。

```
aws lambda get-durable-execution \
  --durable-execution-arn arn:aws:lambda:us-east-1:123456789012:function:myDurableFunction:my-function-version/durable-execution/my-execution-name/my-execution-id
```

**実行履歴を取得する**  
実行のチェックポイント履歴を表示します。

```
aws lambda get-durable-execution-history \
  --durable-execution-arn arn:aws:lambda:us-east-1:123456789012:function:myDurableFunction:my-function-version/durable-execution/my-execution-name/my-execution-id
```

**実行を停止する**  
実行中の耐久性のある実行を停止します。

```
aws lambda stop-durable-execution \
  --durable-execution-arn arn:aws:lambda:us-east-1:123456789012:function:myDurableFunction:my-function-version/durable-execution/my-execution-name/my-execution-id
```

## 関数コードの更新
<a name="durable-cli-update-function"></a>

耐久性のある関数コードを更新し、新しいバージョンを発行します。

**新しいバージョンを更新して公開する方法**

1. 関数コードを更新します。

   ```
   aws lambda update-function-code \
     --function-name myDurableFunction \
     --zip-file fileb://function.zip
   ```

1. アップデートが完了するまで待機します。

   ```
   aws lambda wait function-updated \
     --function-name myDurableFunction
   ```

1. 新しいバージョンを発行します。

   ```
   aws lambda publish-version \
     --function-name myDurableFunction \
     --description "Updated order processing logic"
   ```

1. 新しいバージョンをポイントするようにエイリアスを更新します。

   ```
   aws lambda update-alias \
     --function-name myDurableFunction \
     --name prod \
     --function-version 2
   ```

**重要**  
開始したバージョンを使用して処理中の実行が継続されます。新しい呼び出しには、更新されたエイリアスバージョンが使用されます。

## 関数ログの表示
<a name="durable-cli-view-logs"></a>

CloudWatch ログで耐久性のある関数のログを確認します。

```
aws logs tail /aws/lambda/myDurableFunction --follow
```

ログをフィルタリングして特定の実行を確認します。

```
aws logs filter-log-events \
  --log-group-name /aws/lambda/myDurableFunction \
  --filter-pattern "exec-abc123"
```

## リソースをクリーンアップする
<a name="durable-cli-cleanup"></a>

耐久性のある関数および関連付けされたリソースを削除します。

```
# Delete the function
aws lambda delete-function --function-name myDurableFunction

# Delete the IAM role policies
aws iam detach-role-policy \
  --role-name durable-function-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

aws iam detach-role-policy \
  --role-name durable-function-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy

# Delete the role
aws iam delete-role --role-name durable-function-role
```

## 次のステップ
<a name="durable-cli-next-steps"></a>

AWS CLI を使用して耐久性のある関数をデプロイした後
+ `list-durable-executions` および `get-durable-execution` コマンドを使用して実行をモニタリングする
+ AWS CloudTrail データイベントでチェックポイントオペレーションを表示する
+ 実行失敗または長時間実行の CloudWatch アラームを設定する
+ シェルスクリプトまたは CI/CD パイプラインを使用してデプロイを自動化する

Lambda の AWS CLI コマンドに関する詳細については、「[AWS CLI コマンドリファレンス](https://docs.aws.amazon.com/cli/latest/reference/lambda/index.html)」を参照してください。

# コードとしてのインフレストラクチャを使用して Lambda の耐久性のある関数をデプロイする
<a name="durable-getting-started-iac"></a>

AWS CloudFormation、AWS CDK、AWS Serverless Application Model、Terraform などの Infrastructure as Code (IaC) ツールを使用して Lambda の耐久性のある関数はデプロイできます。これらのツールを使用するとコードで関数、実行ロール、アクセス許可を定義し、デプロイを反復可能でバージョン管理できます。

3 つのツールはすべて以下の内容が必要です。
+ 関数に耐久性のある実行を有効にする
+ 実行ロールにチェックポイントのアクセス許可を付与する
+ バージョンを発行するか、エイリアスを作成する (耐久性のある関数には修飾 ARN が必要)

## ZIP からの耐久性のある関数
<a name="durable-iac-zip"></a>

### AWS CloudFormation
<a name="durable-iac-cloudformation"></a>

CloudFormation を使用して、テンプレートの耐久性のある関数を定義します。次の例では、必要なアクセス許可を持つ耐久性のある関数を作成します。

```
AWSTemplateFormatVersion: '2010-09-09'
Description: Lambda durable function example

Resources:
  DurableFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'		 	 	 
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy

  DurableFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: myDurableFunction
      Runtime: nodejs22.x
      Handler: index.handler
      Role: !GetAtt DurableFunctionRole.Arn
      Code:
        ZipFile: |
          // Your durable function code here
          export const handler = async (event, context) => {
            return { statusCode: 200 };
          };
      DurableConfig:
        ExecutionTimeout: 3600
        RetentionPeriodInDays: 7

  DurableFunctionVersion:
    Type: AWS::Lambda::Version
    Properties:
      FunctionName: !Ref DurableFunction
      Description: Initial version

  DurableFunctionAlias:
    Type: AWS::Lambda::Alias
    Properties:
      FunctionName: !Ref DurableFunction
      FunctionVersion: !GetAtt DurableFunctionVersion.Version
      Name: prod

Outputs:
  FunctionArn:
    Description: Durable function ARN
    Value: !GetAtt DurableFunction.Arn
  AliasArn:
    Description: Function alias ARN (use this for invocations)
    Value: !Ref DurableFunctionAlias
```

**テンプレートをデプロイするには**

```
aws cloudformation deploy \
  --template-file template.yaml \
  --stack-name my-durable-function-stack \
  --capabilities CAPABILITY_IAM
```

### AWS CDK
<a name="durable-iac-cdk"></a>

AWS CDK では、プログラミング言語を使用してインフラストラクチャを定義できます。次の例では、TypeScript および Python を使用して耐久性のある関数を作成する方法が示されます。

------
#### [ TypeScript ]

```
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

export class DurableFunctionStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create the durable function
    const durableFunction = new lambda.Function(this, 'DurableFunction', {
      runtime: lambda.Runtime.NODEJS_22_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda'),
      functionName: 'myDurableFunction',
      durableConfig: { executionTimeout: Duration.hours(1), retentionPeriod: Duration.days(30) },
    });

    // Create version and alias
    const version = durableFunction.currentVersion;
    const alias = new lambda.Alias(this, 'ProdAlias', {
      aliasName: 'prod',
      version: version,
    });

    // Output the alias ARN
    new cdk.CfnOutput(this, 'FunctionAliasArn', {
      value: alias.functionArn,
      description: 'Use this ARN to invoke the durable function',
    });
  }
}
```

------
#### [ Python ]

```
from aws_cdk import (
    Stack,
    aws_lambda as lambda_,
    aws_iam as iam,
    CfnOutput,
)
from constructs import Construct

class DurableFunctionStack(Stack):
    def __init__(self, scope: Construct, id: str, **kwargs):
        super().__init__(scope, id, **kwargs)

        # Create the durable function
        durable_function = lambda_.Function(
            self, 'DurableFunction',
            runtime=lambda_.Runtime.NODEJS_22_X,
            handler='index.handler',
            code=lambda_.Code.from_asset('lambda'),
            function_name='myDurableFunction',
            durable_execution={execution_timeout: Duration.hours(1), retention_period: Duration.days(30)}
        )

        # Add durable execution managed policy for checkpoint permissions
        durable_function.role.add_managed_policy(
            iam.ManagedPolicy.from_aws_managed_policy_name('service-role/AWSLambdaBasicDurableExecutionRolePolicy')
        )

        # Create version and alias
        version = durable_function.current_version
        alias = lambda_.Alias(
            self, 'ProdAlias',
            alias_name='prod',
            version=version
        )

        # Output the alias ARN
        CfnOutput(
            self, 'FunctionAliasArn',
            value=alias.function_arn,
            description='Use this ARN to invoke the durable function'
        )
```

------

**CDK スタックをデプロイする方法**

```
cdk deploy
```

### AWS Serverless Application Model
<a name="durable-iac-sam"></a>

AWS SAM は、サーバーレスアプリケーションの CloudFormation テンプレートを簡素化します。次のテンプレートは、AWS SAM を使用して耐久性のある関数を作成します。

```
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Lambda durable function with SAM

Resources:
  DurableFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: myDurableFunction
      Runtime: nodejs22.x
      Handler: index.handler
      CodeUri: ./src
      DurableConfig:
        ExecutionTimeout: 3600
        RetentionPeriodInDays: 7
      Policies:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy
      AutoPublishAlias: prod

Outputs:
  FunctionArn:
    Description: Durable function ARN
    Value: !GetAtt DurableFunction.Arn
  AliasArn:
    Description: Function alias ARN (use this for invocations)
    Value: !Ref DurableFunction.Alias
```

**SAM テンプレートをデプロイする方法**

```
sam build
sam deploy --guided
```

### Terraform
<a name="durable-iac-terraform"></a>

Terraform は、AWS リソースをサポートする一般的なオープンソース IaC ツールです。次の例では、AWS プロバイダーバージョン 6.25.0 以降を使用して Terraform で耐久性のある関数を作成します。

```
terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 6.25.0"
    }
  }
}

provider "aws" {
  region = "us-east-2"
}

# IAM Role for Lambda Function
resource "aws_iam_role" "lambda_role" {
  name = "durable-function-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Principal = {
        Service = "lambda.amazonaws.com"
      }
    }]
  })
}

# Attach durable execution policy for checkpoint operations
resource "aws_iam_role_policy_attachment" "lambda_durable" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy"
  role       = aws_iam_role.lambda_role.name
}

# Lambda Function with Durable Execution enabled
resource "aws_lambda_function" "durable_function" {
  filename      = "function.zip"
  function_name = "myDurableFunction"
  role          = aws_iam_role.lambda_role.arn
  handler       = "index.handler"
  runtime       = "nodejs22.x"
  timeout       = 30
  memory_size   = 512

  durable_config {
    execution_timeout = 900
    retention_period  = 7
  }
}

# Publish a version
resource "aws_lambda_alias" "prod" {
  name             = "prod"
  function_name    = aws_lambda_function.durable_function.function_name
  function_version = aws_lambda_function.durable_function.version
}

output "function_arn" {
  description = "ARN of the Lambda function"
  value       = aws_lambda_function.durable_function.arn
}

output "alias_arn" {
  description = "ARN of the function alias (use this for invocations)"
  value       = aws_lambda_alias.prod.arn
}
```

**Terraform でデプロイするには**

```
terraform init
terraform plan
terraform apply
```

**注記**  
Lambda の耐久性のある関数の Terraform サポートには、AWS プロバイダーバージョン 6.25.0 以降が必要です。古いバージョンを使用している場合は、プロバイダーのバージョンを更新します。

## OCI コンテナイメージからの耐久性のある関数
<a name="durable-iac-oci"></a>

コンテナイメージに基づいて耐久性のある関数を作成することもできます。コンテナイメージを構築する方法については、「[耐久関数のサポートされているランタイム](durable-supported-runtimes.md)」を参照してください。

### AWS CDK
<a name="durable-iac-oci-cdk"></a>

AWS CDK では、プログラミング言語を使用してインフラストラクチャを定義できます。次の例では、コンテナイメージから TypeScript を使用して耐久性のある関数を作成する方法が示されます。

```
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';

export class DurableFunctionStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Create the durable function
    const durableFunction = new lambda.DockerImageFunction(this, 'DurableFunction', {
      code: lambda.DockerImageCode.fromImageAsset('./lambda', {
        platform: cdk.aws_ecr_assets.Platform.LINUX_AMD64,
      }),
      functionName: 'myDurableFunction',
      memorySize: 512,
      timeout: cdk.Duration.seconds(30),
      durableConfig: { executionTimeout: cdk.Duration.hours(1), retentionPeriod: cdk.Duration.days(30) },
    });

    // Create version and alias
    const version = durableFunction.currentVersion;
    const alias = new lambda.Alias(this, 'ProdAlias', {
      aliasName: 'prod',
      version: version,
    });

    // Output the alias ARN
    new cdk.CfnOutput(this, 'FunctionAliasArn', {
      value: alias.functionArn,
      description: 'Use this ARN to invoke the durable function',
    });
  }
}
```

**CDK スタックをデプロイする方法**

```
cdk deploy
```

### AWS Serverless Application Model
<a name="durable-iac-oci-sam"></a>

AWS SAM は、サーバーレスアプリケーションの CloudFormation テンプレートを簡素化します。次のテンプレートは、AWS SAM を使用して耐久性のある関数を作成します。

```
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Lambda durable function with SAM

Resources:
  DurableFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: myDurableFunction
      PackageType: Image
      ImageUri: ./src
      DurableConfig:
        ExecutionTimeout: 3600
        RetentionPeriodInDays: 7
      Policies:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy
      AutoPublishAlias: prod
    Metadata:
      DockerTag: latest
      DockerContext: ./src
      Dockerfile: Dockerfile

Outputs:
  FunctionArn:
    Description: Durable function ARN
    Value: !GetAtt DurableFunction.Arn
  AliasArn:
    Description: Function alias ARN (use this for invocations)
    Value: !Ref DurableFunction.Alias
```

**SAM テンプレートをデプロイする方法**

```
sam build
sam deploy --guided
```

## 一般的な設定パターン
<a name="durable-iac-common-patterns"></a>

どの IaC ツールを使用するかを問わず、耐久性のある関数については次のパターンに従ってください。

**耐久性のある実行を有効にする**  
関数に `DurableConfig` プロパティを設定して、耐久性のある実行を有効にします。このプロパティは、関数を作成する場合にのみ使用できます。既存の関数では耐久性のある実行を有効にできません。

**チェックポイントのアクセス許可を付与する**  
`AWSLambdaBasicDurableExecutionRolePolicy` 管理ポリシーを実行ロールにアタッチします。このポリシーには、必要な `lambda:CheckpointDurableExecutions` および `lambda:GetDurableExecutionState` アクセス許可が含まれます。

**修飾 ARN を使用する**  
関数のバージョンまたはエイリアスを作成します。耐久性のある関数には、呼び出しに修飾 ARN (バージョンまたはエイリアス付) が必要です。AWS SAM で `AutoPublishAlias` を使用するか、CloudFormation、AWS CDK、および Terraform で明示的なバージョンを作成します。

**パッケージの依存関係**  
デプロイパッケージに耐久性のある実行 SDK を含めます。Node.js の場合、`@aws/durable-execution-sdk-js` をインストールします。Python の場合、`aws-durable-execution-sdk-python` をインストールします。

## 次のステップ
<a name="durable-iac-next-steps"></a>

耐久性のある関数をデプロイした後
+ 修飾 ARN (バージョンまたはエイリアス) を使用して関数をテストする
+ [耐久性のある実行] タブの Lambda コンソールで実行の進行状況をモニタリングする
+ AWS CloudTrail データイベントでチェックポイントオペレーションを表示する
+ CloudWatch Logs を表示して、関数の出力と再生動作を確認する

IaC ツールを使用して Lambda 関数のデプロイの詳細については、以下を参照してください。
+ [CloudFormation AWS::Lambda::Function reference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html)
+ [AWS CDK Lambda モジュールのドキュメント](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda-readme.html)
+ [AWS SAM デベロッパーガイド](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html)

# 耐久性のある関数か Step Functions か
<a name="durable-step-functions"></a>

Lambda の耐久性のある関数と AWS Step Functions はどちらも、自動状態管理と障害復旧による信頼性の高いワークフローオーケストレーションを可能にします。デベロッパーのさまざまな好みやアーキテクチャパターンに対応します。耐久性のある関数は Lambda 内のアプリケーション開発用に最適化され、Step Functions は AWS サービス間のワークフローオーケストレーション用に構築されています。

## 耐久性のある関数を使用するタイミング
<a name="durable-sfn-when-durable"></a>

Durable Functions は、次の場合に使用します。
+ チームが標準のプログラミング言語と使い慣れた開発ツールを好む場合
+ アプリケーションロジックが主に Lambda 関数内にある場合
+ コードの実行状態をきめ細かく制御したい場合
+ ワークフローとビジネスロジックが密結合された Lambda 中心のアプリケーションを構築している場合
+ コードとビジュアル/JSON デザイナーを切り替えずにすばやく反復処理したい場合

## Step Functions を使用すべき状況
<a name="durable-sfn-when-step"></a>

Step Functions は、次の場合に使用します。
+ チーム間の可視性に視覚的なワークフロー表現が必要な場合
+ 複数の AWS サービスをオーケストレーションしていて、カスタム SDK コードを使用しないでネイティブに統合したい場合
+ メンテナンス不要のインフラストラクチャ (パッチ適用、ランタイム更新なし) が必要な場合
+ 非技術的な利害関係者がワークフローロジックを理解して検証する必要がある場合

## 決定フレームワーク
<a name="durable-sfn-decision-framework"></a>

次の質問を使用して、どちらのサービスがユースケースに適しているかを判断します。
+ **主に何を重視しますか?** Lambda でのアプリケーション開発 → 耐久性のある関数。AWS 全体でのワークフローオーケストレーション → Step Functions。
+ **好みのプログラミングモデルは何ですか?** 標準プログラミング言語 → 耐久性のある関数。グラフベースの DSL またはビジュアルデザイナー → Step Functions。
+ **関係する AWS サービスはいくつですか?** 主に Lambda → 耐久性のある関数。複数の AWS サービス → Step Functions。
+ **どの開発ツールを使用していますか?** Lambda デベロッパーエクスペリエンス、LLM エージェントを使用した IDE、プログラミング言語固有のユニットテストフレームワーク、AWS SAM、AWS CDK、AWS Toolkit → 耐久性のある関数。ビジュアルワークフロービルダー、ワークフローをモデル化するために AWS CDK → Step Functions。
+ **インフラストラクチャを管理するのは誰ですか?** Lambda 内の柔軟性を希望 → 耐久性のある関数。フルマネージド、メンテナンス不要を希望 → Step Functions。

## 機能の比較
<a name="durable-sfn-comparison"></a>

次の表は、Step Functions と Lambda の耐久性のある関数の主な機能を比較したものです。


| 機能 | AWS Step Functions | Lambda の耐久性のある関数 | 
| --- | --- | --- | 
| 主な焦点 | AWS 全体でのワークフローオーケストレーション | Lambda でのアプリケーション開発 | 
| サービスタイプ | スタンドアロンの専用ワークフローサービス | Lambda 内で実行する | 
| プログラミングモデル | グラフベースの Amazon States Language DSL または AWS CDK | 標準プログラミング言語 (JavaScript/TypeScript、Python) | 
| 開発ツール | コンソール/AWS Toolkit IDE 拡張機能のビジュアルビルダー、AWS CDK | IDE および LLM エージェント内の Lambda DX、ユニットテストフレームワーク、AWS SAM、AWS Toolkit IDE 拡張機能 | 
| 統合 | 220 以上の AWS サービス、16,000 の API | Lambda イベント駆動型プログラミングモデル拡張機能 (イベントソース) | 
| 管理 | フルマネージド、ランタイム非依存、メンテナンス不要 (パッチ適用なし、ランタイム更新なし) | Lambda 環境内で管理 | 
| 次の用途に適しています | ビジネスプロセスと IT の自動化、データ処理、AI ワークフロー | 分散トランザクション、ステートフルアプリケーションロジック、関数オーケストレーション、データ処理、AI ワークフロー | 

## ハイブリッドアーキテクチャ
<a name="durable-sfn-hybrid"></a>

多くのアプリケーションは、両方のサービスを使用する利点があります。一般的なパターンとしては、耐久性のある関数は Lambda 内のアプリケーションレベルのロジックに使用し、Step Functions は Lambda 関数以外の複数の AWS サービスにわたって高レベルのワークフローを調整します。

## 移行に関する考慮事項
<a name="durable-sfn-migration"></a>

**シンプルに開始し、複雑に進化:** Lambda 中心のワークフローに耐久性のある関数から始めます。マルチサービスオーケストレーションまたはビジュアルワークフロー設計が必要になったら、Step Functions を追加します。

**既存の Step Functions ユーザー:** 確立されたクロスサービスワークフローのために Step Functions を保持します。信頼性を必要とする新しい Lambda アプリケーションロジックには、耐久性のある関数を検討してください。

## 関連リソース
<a name="durable-sfn-related"></a>
+ [Lambda の耐久性のある関数](durable-functions.md)
+ [Step Functions を使用した Lambda 関数のオーケストレーション](with-step-functions.md)
+ [耐久性のある関数の開始方法](durable-getting-started.md)

# 例とユースケース
<a name="durable-examples"></a>

Lambda の耐久性のある関数により、ステップや待機などの耐久性のあるオペレーションを使用して、耐障害性のある複数ステップのアプリケーションを構築できます。自動チェックポイントおよびチェックポイント再生モデルにより、障害の後に実行が最初から再開始されても完了したチェックポイントがスキップされる場合、進行状況を失わずに、関数は障害から復旧して実行を再開できます。

## 短期間の耐障害性プロセス
<a name="durable-examples-short-lived"></a>

耐久性のある関数を使用して、通常は数分で完了する信頼性の高いオペレーションを構築します。これらのプロセスは長時間のワークフローよりも短くなりますが、分散システム全体で自動チェックポイントおよび耐障害性を活用できます。耐久性のある関数により、個々のサービス呼び出しが失敗しても、複雑なエラー処理や状態管理コードを必要とせず、複数ステップのプロセスが正常に完了します。

一般的なシナリオにはホテルの予約システム、レストランの予約プラットフォーム、ライドシェアの旅行リクエスト、イベントのチケット購入、SaaS サブスクリプションのアップグレードなどが含まれます。これらのシナリオには共通の特性があります。これには、まとまって完了する必要がある複数のサービス呼び出し、一過性の障害に対する自動再試行の必要性、分散システム全体で一貫した状態を維持する要件があります。

### マイクロサービス間の分散トランザクション
<a name="durable-examples-distributed-transactions"></a>

障害時の自動ロールバックにより、複数のサービス間で支払い、インベントリ、配送を調整します。各サービスオペレーションはステップでラップされ、トランザクションでサービスに障害が発生したらどこからでも復旧できます。

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { orderId, amount, items } = event;
    
    // Reserve inventory across multiple warehouses
    const inventory = await context.step("reserve-inventory", async () => {
      return await inventoryService.reserve(items);
    });
    
    // Process payment
    const payment = await context.step("process-payment", async () => {
      return await paymentService.charge(amount);
    });
    
    // Create shipment
    const shipment = await context.step("create-shipment", async () => {
      return await shippingService.createShipment(orderId, inventory);
    });
    
    return { orderId, status: 'completed', shipment };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution

@durable_execution
def lambda_handler(event, context: DurableContext):
    order_id = event['orderId']
    amount = event['amount']
    items = event['items']
    
    # Reserve inventory across multiple warehouses
    inventory = context.step(
        lambda _: inventory_service.reserve(items),
        name='reserve-inventory'
    )
    
    # Process payment
    payment = context.step(
        lambda _: payment_service.charge(amount),
        name='process-payment'
    )
    
    # Create shipment
    shipment = context.step(
        lambda _: shipping_service.create_shipment(order_id, inventory),
        name='create-shipment'
    )
    
    return {'orderId': order_id, 'status': 'completed', 'shipment': shipment}
```

------

いずれかのステップが失敗した場合、関数によって最後に成功したチェックポイントから自動的に再試行されます。支払い処理が一時的に失敗しても、インベントリ予約は保持されます。関数が再試行されると、完了したインベントリステップがスキップされ、支払い処理に直接進みます。重複する予約がなくなり、分散システム全体で一貫した状態が確保されます。

### 複数のステップによる注文処理
<a name="durable-examples-order-processing"></a>

検証、支払い承認、インベントリ割り当て、自動再試行および復旧による履行を通じて注文を処理します。個々のステップが失敗して再試行されても、各ステップはチェックポイントされ、順序が進行されるようにします。

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { orderId, customerId, items } = event;
    
    // Validate order details
    const validation = await context.step("validate-order", async () => {
      const customer = await customerService.validate(customerId);
      const itemsValid = await inventoryService.validateItems(items);
      return { customer, itemsValid };
    });
    
    if (!validation.itemsValid) {
      return { orderId, status: 'rejected', reason: 'invalid_items' };
    }
    
    // Authorize payment
    const authorization = await context.step("authorize-payment", async () => {
      return await paymentService.authorize(
        validation.customer.paymentMethod,
        calculateTotal(items)
      );
    });
    
    // Allocate inventory
    const allocation = await context.step("allocate-inventory", async () => {
      return await inventoryService.allocate(items);
    });
    
    // Fulfill order
    const fulfillment = await context.step("fulfill-order", async () => {
      return await fulfillmentService.createShipment({
        orderId,
        items: allocation.allocatedItems,
        address: validation.customer.shippingAddress
      });
    });
    
    return {
      orderId,
      status: 'completed',
      trackingNumber: fulfillment.trackingNumber
    };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution

@durable_execution
def lambda_handler(event, context: DurableContext):
    order_id = event['orderId']
    customer_id = event['customerId']
    items = event['items']
    
    # Validate order details
    def validate_order(_):
        customer = customer_service.validate(customer_id)
        items_valid = inventory_service.validate_items(items)
        return {'customer': customer, 'itemsValid': items_valid}
    
    validation = context.step(validate_order, name='validate-order')
    
    if not validation['itemsValid']:
        return {'orderId': order_id, 'status': 'rejected', 'reason': 'invalid_items'}
    
    # Authorize payment
    authorization = context.step(
        lambda _: payment_service.authorize(
            validation['customer']['paymentMethod'],
            calculate_total(items)
        ),
        name='authorize-payment'
    )
    
    # Allocate inventory
    allocation = context.step(
        lambda _: inventory_service.allocate(items),
        name='allocate-inventory'
    )
    
    # Fulfill order
    fulfillment = context.step(
        lambda _: fulfillment_service.create_shipment({
            'orderId': order_id,
            'items': allocation['allocatedItems'],
            'address': validation['customer']['shippingAddress']
        }),
        name='fulfill-order'
    )
    
    return {
        'orderId': order_id,
        'status': 'completed',
        'trackingNumber': fulfillment['trackingNumber']
    }
```

------

このパターンにより、注文が中間状態で停止することはありません。検証が失敗した場合、支払い承認の前に注文が拒否されます。支払い承認が失敗した場合、インベントリは割り当てられません。各ステップは、自動再試行および復旧によって前のステップに基づいて構築されます。

**メモ**  
条件付きチェックの `if (!validation.itemsValid)` はステップ外にあり、再生中に再実行されます。これは決定的であるため安全です。同じ検証オブジェクトを前提として、常に同じ結果が生成されます。

## 長時間実行中のプロセス
<a name="durable-examples-long-running"></a>

数時間、数日、数週間に及ぶプロセスには、耐久性のある関数を使用します。待機オペレーションはコンピューティング料金を発生させずに実行を停止するため、長時間のプロセスはコスト効率が優れています。待機期間中、関数は実行を停止して Lambda は実行環境をリサイクルします。再開するとき、Lambda は関数を再度呼び出して最後のチェックポイントから再生します。

人間の決定、外部システムの応答、スケジュールされた処理ウィンドウ、時間ベースの遅延の待機を問わず、この実行モデルによって耐久性のある関数は長期間一時停止する必要があるプロセスには最適です。待機時間ではなく、アクティブなコンピューティング時間に対してのみ支払います。

一般的なシナリオには、ドキュメント承認プロセス、スケジュールされたバッチ処理、複数日間のオンボーディングプロセス、サブスクリプションのトライアルプロセス、遅延通知システムなどが含まれます。これらのシナリオには共通の特性があります。これには、数時間または数日で測定される長い待機期間、その待機時間にわたって実行状態を維持する必要性、アイドル状態のコンピューティング時間に莫大な支払い金額が発生するコスト重視の要件などがあります。

### ヒューマンインザループ承認
<a name="durable-examples-human-in-loop"></a>

実行状態が維持されながら、ドキュメントのレビュー、承認、決定の実行が一時停止されます。この関数はリソースを消費せずに外部コールバックを待機し、承認されると自動的に再開されます。

このパターンは、人間の判断や外部検証が必要なプロセスに不可欠です。関数はコールバックポイントで停止され、待機中にコンピューティング料金は発生しません。誰かが API を介して決定を送信すると、Lambda によって関数が再度呼び出されてチェックポイントから再生され、承認結果で続行されます。

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { documentId, reviewers } = event;
    
    // Step 1: Prepare document for review
    const prepared = await context.step("prepare-document", async () => {
      return await documentService.prepare(documentId);
    });
    
    // Step 2: Request approval with callback
    const approval = await context.waitForCallback(
      "approval-callback",
      async (callbackId) => {
        await notificationService.sendApprovalRequest({
          documentId,
          reviewers,
          callbackId,
          expiresIn: 86400
        });
      },
      {
        timeout: { seconds: 86400 }
      }
    );
    
    // Function resumes here when approval is received
    if (approval?.approved) {
      const finalized = await context.step("finalize-document", async () => {
        return await documentService.finalize(documentId, approval.comments);
      });
      
      return {
        status: 'approved',
        documentId,
        finalizedAt: finalized.timestamp
      };
    }
    
    // Handle rejection
    await context.step("archive-rejected", async () => {
      await documentService.archive(documentId, approval?.reason);
    });
    
    return {
      status: 'rejected',
      documentId,
      reason: approval?.reason
    };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution, WaitConfig

@durable_execution
def lambda_handler(event, context: DurableContext):
    document_id = event['documentId']
    reviewers = event['reviewers']
    
    # Step 1: Prepare document for review
    prepared = context.step(
        lambda _: document_service.prepare(document_id),
        name='prepare-document'
    )
    
    # Step 2: Request approval with callback
    def send_approval_request(callback_id):
        notification_service.send_approval_request({
            'documentId': document_id,
            'reviewers': reviewers,
            'callbackId': callback_id,
            'expiresIn': 86400
        })
    
    approval = context.wait_for_callback(
        send_approval_request,
        name='approval-callback',
        config=WaitConfig(timeout=86400)
    )
    
    # Function resumes here when approval is received
    if approval and approval.get('approved'):
        finalized = context.step(
            lambda _: document_service.finalize(document_id, approval.get('comments')),
            name='finalize-document'
        )
        
        return {
            'status': 'approved',
            'documentId': document_id,
            'finalizedAt': finalized['timestamp']
        }
    
    # Handle rejection
    context.step(
        lambda _: document_service.archive(document_id, approval.get('reason') if approval else None),
        name='archive-rejected'
    )
    
    return {
        'status': 'rejected',
        'documentId': document_id,
        'reason': approval.get('reason') if approval else None
    }
```

------

コールバックが受信されて関数が再開されると、最初から再生されます。prepare-document のステップでは、チェックポイントされた結果が即時に返されます。waitForCallback オペレーションでは、再度待機せずに、保存された承認結果とともに即時に返されます。その後、実行は確定またはアーカイブのステップに進みます。

### マルチステージデータのパイプライン
<a name="durable-examples-data-pipelines"></a>

ステージ間のチェックポイントを使用して、抽出、変換、読み込みフェーズによって大量のデータセットを処理します。各ステージは完了するまで数時間かかる場合があります。中断された場合、チェックポイントにより、どのステージからでもパイプラインを再開できます。

このパターンは ETL ワークフロー、データ移行、ステージ間に復旧ポイントがある状態でデータを段階的に処理する必要があるバッチ処理ジョブに最適です。ステージが失敗した場合、パイプラインは最初から再開始されるのではなく、最後に完了したステージから再開されます。待機オペレーションを使用してステージ間で一時停止することもできます。レート制限の遵守、ダウンストリームシステムの準備の待機、オフピーク時に処理のスケジューリングを行えます。

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { datasetId, batchSize } = event;
    
    // Stage 1: Extract data from source
    const extracted = await context.step("extract-data", async () => {
      const records = await sourceDatabase.extractRecords(datasetId);
      return { recordCount: records.length, records };
    });
    
    // Wait 5 minutes to respect source system rate limits
    await context.wait({ seconds: 300 });
    
    // Stage 2: Transform data in batches
    const transformed = await context.step("transform-data", async () => {
      const batches = chunkArray(extracted.records, batchSize);
      const results = [];
      
      for (const batch of batches) {
        const transformed = await transformService.processBatch(batch);
        results.push(transformed);
      }
      
      return { batchCount: batches.length, results };
    });
    
    // Wait until off-peak hours (e.g., 2 AM)
    const now = new Date();
    const targetHour = 2;
    const msUntilTarget = calculateMsUntilHour(now, targetHour);
    await context.wait({ seconds: Math.floor(msUntilTarget / 1000) });
    
    // Stage 3: Load data to destination
    const loaded = await context.step("load-data", async () => {
      let loadedCount = 0;
      
      for (const result of transformed.results) {
        await destinationDatabase.loadBatch(result);
        loadedCount += result.length;
      }
      
      return { loadedCount };
    });
    
    // Stage 4: Verify and finalize
    const verified = await context.step("verify-pipeline", async () => {
      const verification = await destinationDatabase.verifyRecords(datasetId);
      await pipelineService.markComplete(datasetId, verification);
      return verification;
    });
    
    return {
      datasetId,
      recordsProcessed: extracted.recordCount,
      batchesProcessed: transformed.batchCount,
      recordsLoaded: loaded.loadedCount,
      verified: verified.success
    };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution
from datetime import datetime

@durable_execution
def lambda_handler(event, context: DurableContext):
    dataset_id = event['datasetId']
    batch_size = event['batchSize']
    
    # Stage 1: Extract data from source
    def extract_data(_):
        records = source_database.extract_records(dataset_id)
        return {'recordCount': len(records), 'records': records}
    
    extracted = context.step(extract_data, name='extract-data')
    
    # Wait 5 minutes to respect source system rate limits
    context.wait(300)
    
    # Stage 2: Transform data in batches
    def transform_data(_):
        batches = chunk_array(extracted['records'], batch_size)
        results = []
        
        for batch in batches:
            transformed = transform_service.process_batch(batch)
            results.append(transformed)
        
        return {'batchCount': len(batches), 'results': results}
    
    transformed = context.step(transform_data, name='transform-data')
    
    # Wait until off-peak hours (e.g., 2 AM)
    now = datetime.now()
    target_hour = 2
    ms_until_target = calculate_ms_until_hour(now, target_hour)
    context.wait(ms_until_target // 1000)
    
    # Stage 3: Load data to destination
    def load_data(_):
        loaded_count = 0
        
        for result in transformed['results']:
            destination_database.load_batch(result)
            loaded_count += len(result)
        
        return {'loadedCount': loaded_count}
    
    loaded = context.step(load_data, name='load-data')
    
    # Stage 4: Verify and finalize
    def verify_pipeline(_):
        verification = destination_database.verify_records(dataset_id)
        pipeline_service.mark_complete(dataset_id, verification)
        return verification
    
    verified = context.step(verify_pipeline, name='verify-pipeline')
    
    return {
        'datasetId': dataset_id,
        'recordsProcessed': extracted['recordCount'],
        'batchesProcessed': transformed['batchCount'],
        'recordsLoaded': loaded['loadedCount'],
        'verified': verified['success']
    }
```

------

各ステージはステップでラップされ、中断された場合にパイプラインがどのステージでも再開できるチェックポイントが作成されます。抽出と変換の間の 5 分待機は、コンピューティングリソースを消費せずにソースシステムのレート制限を遵守しますが、午前 2 時までの待機はオフピーク時に高価な読み込みオペレーションをスケジューリングします。

**メモ**  
`new Date()` 呼び出しおよび `calculateMsUntilHour()` 関数はステップ外にあり、再生中に再実行されます。再生間で一貫性を持たせる必要がある時間ベースのオペレーションには、ステップ内のタイムスタンプを計算するか、待機時間 (チェックポイントの対象になる) にのみ使用します。

## 高度なパターン
<a name="durable-examples-advanced"></a>

耐久性のある関数を使用して、複数の耐久性のあるオペレーション、並列実行、配列処理、条件付きロジック、ポーリングを組み合わせた複雑な複数ステップのアプリケーションを構築します。これらのパターンにより、耐障害性および自動復旧を維持しながら、多くのタスクを調整する高度なアプリケーションを構築できます。

高度なパターンは、単純なシーケンシャルステップを超えます。オペレーションは `parallel()` と同時に実行し、`map()` で配列を処理し、`waitForCondition()` で外部条件を待機し、これらのプリミティブを組み合わせて信頼性の高いアプリケーションを構築できます。耐久性のある各オペレーションに独自のチェックポイントが作成されるため、アプリケーションが中断されたらどこからでも復旧できます。

### ユーザーのオンボーディングプロセス
<a name="durable-examples-user-onboarding"></a>

登録、E メール認証、プロフィール設定、再試行処理による初期設定を通じてユーザーを案内します。この例では、シーケンシャルステップ、コールバック、条件付きロジックを組み合わせて、完全なオンボーディングプロセスを作成します。

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { userId, email } = event;
    
    // Step 1: Create user account
    const user = await context.step("create-account", async () => {
      return await userService.createAccount(userId, email);
    });
    
    // Step 2: Send verification email
    await context.step("send-verification", async () => {
      return await emailService.sendVerification(email);
    });
    
    // Step 3: Wait for email verification (up to 48 hours)
    const verified = await context.waitForCallback(
      "email-verification",
      async (callbackId) => {
        await notificationService.sendVerificationLink({
          email,
          callbackId,
          expiresIn: 172800
        });
      },
      {
        timeout: { seconds: 172800 }
      }
    );
    
    if (!verified) {
      await context.step("send-reminder", async () => {
        await emailService.sendReminder(email);
      });
      
      return {
        status: "verification_timeout",
        userId,
        message: "Email verification not completed within 48 hours"
      };
    }
    
    // Step 4: Initialize user profile in parallel
    const setupResults = await context.parallel("profile-setup", [
      async (ctx: DurableContext) => {
        return await ctx.step("create-preferences", async () => {
          return await preferencesService.createDefaults(userId);
        });
      },
      
      async (ctx: DurableContext) => {
        return await ctx.step("setup-notifications", async () => {
          return await notificationService.setupDefaults(userId);
        });
      },
      
      async (ctx: DurableContext) => {
        return await ctx.step("create-welcome-content", async () => {
          return await contentService.createWelcome(userId);
        });
      }
    ]);
    
    // Step 5: Send welcome email
    await context.step("send-welcome", async () => {
      const [preferences, notifications, content] = setupResults.getResults();
      return await emailService.sendWelcome({
        email,
        preferences,
        notifications,
        content
      });
    });
    
    return {
      status: "onboarding_complete",
      userId,
      completedAt: new Date().toISOString()
    };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution, WaitConfig
from datetime import datetime

@durable_execution
def lambda_handler(event, context: DurableContext):
    user_id = event['userId']
    email = event['email']
    
    # Step 1: Create user account
    user = context.step(
        lambda _: user_service.create_account(user_id, email),
        name='create-account'
    )
    
    # Step 2: Send verification email
    context.step(
        lambda _: email_service.send_verification(email),
        name='send-verification'
    )
    
    # Step 3: Wait for email verification (up to 48 hours)
    def send_verification_link(callback_id):
        notification_service.send_verification_link({
            'email': email,
            'callbackId': callback_id,
            'expiresIn': 172800
        })
    
    verified = context.wait_for_callback(
        send_verification_link,
        name='email-verification',
        config=WaitConfig(timeout=172800)
    )
    
    if not verified:
        context.step(
            lambda _: email_service.send_reminder(email),
            name='send-reminder'
        )
        
        return {
            'status': 'verification_timeout',
            'userId': user_id,
            'message': 'Email verification not completed within 48 hours'
        }
    
    # Step 4: Initialize user profile in parallel
    def create_preferences(ctx: DurableContext):
        return ctx.step(
            lambda _: preferences_service.create_defaults(user_id),
            name='create-preferences'
        )
    
    def setup_notifications(ctx: DurableContext):
        return ctx.step(
            lambda _: notification_service.setup_defaults(user_id),
            name='setup-notifications'
        )
    
    def create_welcome_content(ctx: DurableContext):
        return ctx.step(
            lambda _: content_service.create_welcome(user_id),
            name='create-welcome-content'
        )
    
    setup_results = context.parallel(
        [create_preferences, setup_notifications, create_welcome_content],
        name='profile-setup'
    )
    
    # Step 5: Send welcome email
    def send_welcome(_):
        results = setup_results.get_results()
        preferences, notifications, content = results[0], results[1], results[2]
        return email_service.send_welcome({
            'email': email,
            'preferences': preferences,
            'notifications': notifications,
            'content': content
        })
    
    context.step(send_welcome, name='send-welcome')
    
    return {
        'status': 'onboarding_complete',
        'userId': user_id,
        'completedAt': datetime.now().isoformat()
    }
```

------

このプロセスでは、アカウント作成と E メール検証のためにシーケンシャルステップとチェックポイントを組み合わせたら、リソースを消費せずに E メール認証を待機するため、最大 48 時間一時停止します。検証の完了またはタイムアウトに基づき、条件付きロジックは異なるパスを処理します。プロファイルのセットアップタスクは並列オペレーションを使用して同時に実行され、合計実行時間を短縮します。各ステップは一過性の障害時に自動的に再試行され、オンボーディングが確実に完了します。

### 関数の連鎖呼び出し
<a name="durable-examples-chained-invocations"></a>

`context.invoke()` を使用して、耐久性のある関数内で他の Lambda 関数を呼び出します。呼び出される関数が完了するまで、呼び出し元の関数は待機しながら停止し、結果を保持するチェックポイントが作成されます。呼び出される関数が完了した後に呼び出し元の関数が中断された場合、関数を再呼び出しせずに、保存された結果で再開されます。

特定のドメイン (顧客検証、支払い処理、インベントリ管理) を処理する特殊な関数を持って、ワークフローで調整する必要があるときに、このパターンを使用します。各関数は独自のロジックを維持し、複数のオーケストレーター関数で呼び出すことができるため、コードの重複を回避できます。

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

// Main orchestrator function
export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { orderId, customerId } = event;
    
    // Step 1: Validate customer by invoking customer service function
    const customer = await context.invoke(
      "validate-customer",
      "arn:aws:lambda:us-east-1:123456789012:function:customer-service:1",
      { customerId }
    );
    
    if (!customer.isValid) {
      return { orderId, status: "rejected", reason: "invalid_customer" };
    }
    
    // Step 2: Check inventory by invoking inventory service function
    const inventory = await context.invoke(
      "check-inventory",
      "arn:aws:lambda:us-east-1:123456789012:function:inventory-service:1",
      { orderId, items: event.items }
    );
    
    if (!inventory.available) {
      return { orderId, status: "rejected", reason: "insufficient_inventory" };
    }
    
    // Step 3: Process payment by invoking payment service function
    const payment = await context.invoke(
      "process-payment",
      "arn:aws:lambda:us-east-1:123456789012:function:payment-service:1",
      {
        customerId,
        amount: inventory.totalAmount,
        paymentMethod: customer.paymentMethod
      }
    );
    
    // Step 4: Create shipment by invoking fulfillment service function
    const shipment = await context.invoke(
      "create-shipment",
      "arn:aws:lambda:us-east-1:123456789012:function:fulfillment-service:1",
      {
        orderId,
        items: inventory.allocatedItems,
        address: customer.shippingAddress
      }
    );
    
    return {
      orderId,
      status: "completed",
      trackingNumber: shipment.trackingNumber,
      estimatedDelivery: shipment.estimatedDelivery
    };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution

# Main orchestrator function
@durable_execution
def lambda_handler(event, context: DurableContext):
    order_id = event['orderId']
    customer_id = event['customerId']
    
    # Step 1: Validate customer by invoking customer service function
    customer = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:customer-service:1',
        {'customerId': customer_id},
        name='validate-customer'
    )
    
    if not customer['isValid']:
        return {'orderId': order_id, 'status': 'rejected', 'reason': 'invalid_customer'}
    
    # Step 2: Check inventory by invoking inventory service function
    inventory = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:inventory-service:1',
        {'orderId': order_id, 'items': event['items']},
        name='check-inventory'
    )
    
    if not inventory['available']:
        return {'orderId': order_id, 'status': 'rejected', 'reason': 'insufficient_inventory'}
    
    # Step 3: Process payment by invoking payment service function
    payment = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:payment-service:1',
        {
            'customerId': customer_id,
            'amount': inventory['totalAmount'],
            'paymentMethod': customer['paymentMethod']
        },
        name='process-payment'
    )
    
    # Step 4: Create shipment by invoking fulfillment service function
    shipment = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:fulfillment-service:1',
        {
            'orderId': order_id,
            'items': inventory['allocatedItems'],
            'address': customer['shippingAddress']
        },
        name='create-shipment'
    )
    
    return {
        'orderId': order_id,
        'status': 'completed',
        'trackingNumber': shipment['trackingNumber'],
        'estimatedDelivery': shipment['estimatedDelivery']
    }
```

------

各呼び出しでは、オーケストレーター関数にチェックポイントが作成されます。顧客検証の完了後にオーケストレーターが中断された場合、保存された顧客データを使用してそのチェックポイントから再開され、検証呼び出しがスキップされます。これにより、ダウンストリームサービスへの重複呼び出しが防止され、中断しても一貫した実行が実現されます。

呼び出される関数は、耐久性のある Lambda 関数または標準の Lambda 関数のいずれかの場合があります。耐久性のある関数を呼び出した場合、待機やチェックポイントを含む独自の複数ステップのワークフローを持つことがあります。オーケストレーターは耐久性のある完全な実行が終了されるまで待ち、最終結果を受け取ります。

**注記**  
クロスアカウントの呼び出しはサポートされていません。呼び出されるすべての関数は、呼び出し元の関数と同じ AWS アカウントに存在する必要があります。

### チェックポイントを使用したバッチ処理
<a name="durable-examples-batch-processing"></a>

障害の後に最後に成功したチェックポイントでの自動復旧により、数百万件のレコードを処理します。この例では、耐久性のある関数が `map()` オペレーションをチャンキングおよびレート制限と組み合わて、大規模なデータ処理に対応する方法が示されます。

------
#### [ TypeScript ]

```
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";

interface Batch {
  batchIndex: number;
  recordIds: string[];
}

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    const { datasetId, batchSize = 1000 } = event;
    
    // Step 1: Get all record IDs to process
    const recordIds = await context.step("fetch-record-ids", async () => {
      return await dataService.getRecordIds(datasetId);
    });
    
    // Step 2: Split into batches
    const batches: Batch[] = [];
    for (let i = 0; i < recordIds.length; i += batchSize) {
      batches.push({
        batchIndex: Math.floor(i / batchSize),
        recordIds: recordIds.slice(i, i + batchSize)
      });
    }
    
    // Step 3: Process batches with controlled concurrency
    const batchResults = await context.map(
      "process-batches",
      batches,
      async (ctx: DurableContext, batch: Batch, index: number) => {
        const processed = await ctx.step(`batch-${batch.batchIndex}`, async () => {
          const results = [];
          for (const recordId of batch.recordIds) {
            const result = await recordService.process(recordId);
            results.push(result);
          }
          return results;
        });
        
        const validated = await ctx.step(`validate-${batch.batchIndex}`, async () => {
          return await validationService.validateBatch(processed);
        });
        
        return {
          batchIndex: batch.batchIndex,
          recordCount: batch.recordIds.length,
          successCount: validated.successCount,
          failureCount: validated.failureCount
        };
      },
      {
        maxConcurrency: 5
      }
    );
    
    // Step 4: Aggregate results
    const summary = await context.step("aggregate-results", async () => {
      const results = batchResults.getResults();
      const totalSuccess = results.reduce((sum, r) => sum + r.successCount, 0);
      const totalFailure = results.reduce((sum, r) => sum + r.failureCount, 0);
      
      return {
        datasetId,
        totalRecords: recordIds.length,
        batchesProcessed: batches.length,
        successCount: totalSuccess,
        failureCount: totalFailure,
        completedAt: new Date().toISOString()
      };
    });
    
    return summary;
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import DurableContext, durable_execution, MapConfig
from datetime import datetime
from typing import List, Dict

@durable_execution
def lambda_handler(event, context: DurableContext):
    dataset_id = event['datasetId']
    batch_size = event.get('batchSize', 1000)
    
    # Step 1: Get all record IDs to process
    record_ids = context.step(
        lambda _: data_service.get_record_ids(dataset_id),
        name='fetch-record-ids'
    )
    
    # Step 2: Split into batches
    batches = []
    for i in range(0, len(record_ids), batch_size):
        batches.append({
            'batchIndex': i // batch_size,
            'recordIds': record_ids[i:i + batch_size]
        })
    
    # Step 3: Process batches with controlled concurrency
    def process_batch(ctx: DurableContext, batch: Dict, index: int):
        batch_index = batch['batchIndex']
        
        def process_records(_):
            results = []
            for record_id in batch['recordIds']:
                result = record_service.process(record_id)
                results.append(result)
            return results
        
        processed = ctx.step(process_records, name=f'batch-{batch_index}')
        
        validated = ctx.step(
            lambda _: validation_service.validate_batch(processed),
            name=f'validate-{batch_index}'
        )
        
        return {
            'batchIndex': batch_index,
            'recordCount': len(batch['recordIds']),
            'successCount': validated['successCount'],
            'failureCount': validated['failureCount']
        }
    
    batch_results = context.map(
        process_batch,
        batches,
        name='process-batches',
        config=MapConfig(max_concurrency=5)
    )
    
    # Step 4: Aggregate results
    def aggregate_results(_):
        results = batch_results.get_results()
        total_success = sum(r['successCount'] for r in results)
        total_failure = sum(r['failureCount'] for r in results)
        
        return {
            'datasetId': dataset_id,
            'totalRecords': len(record_ids),
            'batchesProcessed': len(batches),
            'successCount': total_success,
            'failureCount': total_failure,
            'completedAt': datetime.now().isoformat()
        }
    
    summary = context.step(aggregate_results, name='aggregate-results')
    
    return summary
```

------

レコードは管理可能なバッチに分割され、メモリやダウンストリームサービスの圧迫を回避します。その後に複数のバッチが並列処理され、`maxConcurrency` によって同時処理が制御されます。各バッチには独自のチェックポイントがあるため、失敗はすべてのレコードで再処理されるのではなく、失敗したバッチのみで再試行されます。このパターンは処理に数時間かかる可能性がある ETL ジョブ、データ移行、一括操作に最適です。

## 次のステップ
<a name="durable-examples-next-steps"></a>
+ DurableContext、ステップ、待機を理解するため、「[基本的な概念](durable-basic-concepts.md)」を確認する
+ 決定的なコードを記述してパフォーマンスを最適化するには、「[ベストプラクティス](durable-best-practices.md)」を確認する
+ ローカルおよびクラウドで[耐久性のある機能のテスト](durable-testing.md)を実行する方法に関する詳細
+ 耐久性のある関数と Step Functions を比較して、各アプローチがどのような場合に最も効果的かを明らかにします。「[耐久性のある関数か Step Functions か](durable-step-functions.md)」を参照してください。

# Lambda 耐久関数のセキュリティとアクセス許可
<a name="durable-security"></a>

Lambda 耐久関数には、チェックポイントオペレーションを管理するための特定の IAM アクセス許可が必要です。関数に必要なアクセス許可のみを付与することで、最小特権の原則に従います。

## 実行ロールのアクセス許可
<a name="durable-execution-role"></a>

耐久関数の実行ロールには、チェックポイントを作成し、実行状態を取得するためのアクセス許可が必要です。次のポリシーは、必要な最低限のアクセス許可を示しています。

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:CheckpointDurableExecution",
                "lambda:GetDurableExecutionState"
            ],
            "Resource": "arn:aws:lambda:region:account-id:function:function-name:*"
        }
    ]
}
```

コンソールを使用して耐久関数を作成すると、Lambda はこれらのアクセス許可を実行ロールに自動的に追加します。AWS CLI または AWS CloudFormation を使用して関数を作成する場合は、これらのアクセス許可を実行ロールに追加します。

**最小特権の原則**  
ワイルドカードを使用する代わりに、`Resource` 要素を特定の関数 ARN にスコープします。これにより、実行ロールは、それらを必要とする関数のみのチェックポイントオペレーションに制限されます。

**例: 複数の関数のスコープ付きアクセス許可**

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:CheckpointDurableExecution",
                "lambda:GetDurableExecutionState"
            ],
            "Resource": [
                "arn:aws:lambda:us-east-1:123456789012:function:orderProcessor:*",
                "arn:aws:lambda:us-east-1:123456789012:function:paymentHandler:*"
            ]
        }
    ]
}
```

または、耐久性のある実行の必要なアクセス許可と Amazon CloudWatch Logs の基本的な Lambda 実行アクセス許可を含む AWS マネージドポリシー `AWSLambdaBasicDurableExecutionRolePolicy` を使用することもできます。

## 状態の暗号化
<a name="durable-state-encryption"></a>

Lambda 耐久関数は、AWS 所有キーを使用して保管中の暗号化を無料で自動的に有効にします。各関数の実行は、他の実行がアクセスできない分離された状態を維持します。カスタマーマネージドキー (CMK) はサポートされていません。

チェックポイントデータには以下が含まれます。
+ ステップの結果と戻り値
+ 実行の進行状況とタイムライン
+ 待機状態情報

Lambda がチェックポイントデータを読み取りまたは書き込みするときに、すべてのデータは TLS を使用して転送中に暗号化されます。

### カスタムシリアライザーとデシリアライザーによるカスタム暗号化
<a name="durable-custom-encryption"></a>

重要なセキュリティ要件については、カスタムシリアライザーと耐久性のある SDK を使用するデシリアライザー (SerDer) を使用して、独自の暗号化および復号メカニズムを実装できます。このアプローチにより、チェックポイントデータの保護に使用される暗号化キーとアルゴリズムを完全に制御できます。

**重要**  
カスタム暗号化を使用すると、Lambda コンソールや API レスポンスで操作結果を確認できなくなります。チェックポイントデータは実行履歴に暗号化されて表示され、復号化なしでは検査できません。

関数の実行ロールには、カスタム SerDer 実装で使用される AWS KMS キーの `kms:Encrypt`と `kms:Decrypt` アクセス許可が必要です。

## CloudTrail ロギング
<a name="durable-cloudtrail-logging"></a>

Lambda は、チェックポイントオペレーションを AWS CloudTrail のデータイベントとしてログに記録します。CloudTrail を使用して、チェックポイントが作成された際の監査、実行状態の変更の追跡、耐久性のある実行データへのアクセスのモニタリングを行うことができます。

チェックポイントオペレーションは、以下のイベント名で CloudTrail ログに表示されます。
+ `CheckpointDurableExecution` – ステップが完了し、チェックポイントが作成されるとログに記録されます
+ `GetDurableExecutionState` – Lambda がリプレイ中に実行状態を取得するとログに記録されます

耐久関数のデータイベントログ記録を有効にするには、Lambda データイベントをログに記録するように CloudTrail 証跡を設定します。詳細については、「CloudTrail ユーザーガイド」の「[Logging data events](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-data-events-with-cloudtrail.html)」を参照してください。

**例: チェックポイントオペレーションの CloudTrail ログエントリ**

```
{
    "eventVersion": "1.08",
    "eventTime": "2024-11-16T10:30:45Z",
    "eventName": "CheckpointDurableExecution",
    "eventSource": "lambda.amazonaws.com",
    "requestParameters": {
        "functionName": "myDurableFunction",
        "executionId": "exec-abc123",
        "stepId": "step-1"
    },
    "responseElements": null,
    "eventType": "AwsApiCall"
}
```

## クロスアカウントに関する考慮事項
<a name="durable-cross-account-access"></a>

AWS アカウント間で耐久関数を呼び出す場合、呼び出し元のアカウントには `lambda:InvokeFunction` アクセス許可が必要ですが、チェックポイントオペレーションは常に関数のアカウントで実行ロールを使用します。呼び出し元のアカウントは、チェックポイントデータまたは実行状態に直接アクセスできません。

この分離により、外部アカウントから呼び出された場合でも、チェックポイントデータは関数のアカウント内で安全に保たれます。

## 継承された Lambda セキュリティ機能
<a name="durable-inherited-security"></a>

耐久関数は、VPC 接続、環境変数暗号化、デッドレターキュー、予約された同時実行、関数 URL、コード署名、コンプライアンス証明書 (SOC、PCI DSS、HIPAA など) など、Lambda からすべてのセキュリティ、ガバナンス、コンプライアンス機能を継承します。

Lambda セキュリティ機能の詳細については、「Lambda デベロッパーガイド」の「[AWS Lambda のセキュリティ](https://docs.aws.amazon.com/lambda/latest/dg/lambda-security.html)」を参照してください。耐久関数に関する追加のセキュリティ上の考慮事項は、このガイドに記載されているチェックポイントのアクセス許可のみです。

# 耐久性のある実行 SDK
<a name="durable-execution-sdk"></a>

耐久性のある実行 SDK は、耐久性のある関数を構築するための基盤です。進行状況のチェックポイント、再試行の処理、実行フローの管理に必要なプリミティブが提供されます。SDK によってチェックポイントの管理および再生の複雑さが抽象化されるため、自動的に耐障害性になるシーケンシャルコードを記述できます。

SDK は JavaScript、TypeScript、Java（プレビュー）に対応しています。API の完全なドキュメントや例については、GitHub の「[JavaScript/TypeScript SDK](https://github.com/aws/aws-durable-execution-sdk-js)」、「[Python SDK](https://github.com/aws/aws-durable-execution-sdk-python)」、「[Java SDK](https://github.com/aws/aws-durable-execution-sdk-java)」を参照してください。

## DurableContext
<a name="durable-sdk-context"></a>

SDK により、耐久性のあるすべてのオペレーションが公開される `DurableContext` オブジェクトで関数に提供されます。このコンテキストは標準 Lambda コンテキストを置き換えて、チェックポイントの作成、実行フローの管理、外部システムとの調整に関する方法を説明します。

SDK を使用するには、Lambda ハンドラーを耐久性のある実行ラッパーでラップします。

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Your function receives DurableContext instead of Lambda context
    // Use context.step(), context.wait(), etc.
    return result;
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext

@durable_execution
def handler(event: dict, context: DurableContext):
    # Your function receives DurableContext
    # Use context.step(), context.wait(), etc.
    return result
```

------
#### [ Java (Preview) ]

```
import software.amazon.lambda.durable.DurableContext;
import software.amazon.lambda.durable.DurableHandler;

public class Handler extends DurableHandler<Object, String> {
    @Override
    public String handleRequest(Object input, DurableContext context) {
        // Your function receives DurableContext
        // Use context.step(), context.wait(), etc.
        return result;
    }
}
```

------

ラッパーは関数の呼び出しを傍受し、既存のチェックポイントログをロードし、再生およびチェックポイントを管理する `DurableContext` を提供します。

## SDK の動作
<a name="durable-sdk-what-it-does"></a>

SDK により、耐久性のある実行を実現する 3 つの重要な責任が処理されます。

**チェックポイント管理:** 関数が耐久性のあるオペレーションを実行すると、SDK によってチェックポイントが自動的に作成されます。各チェックポイントでは、オペレーションタイプ、入力、結果が記録されます。関数がステップを完了すると、SDK によって続行される前にチェックポイントが保持されます。関数が中断された場合、完了したすべてのオペレーションから再開できます。

**再生の調整:** 一時停止または中断の後に関数が再開されると、SDK によって再生が実行されます。コードを最初から実行しますが、再実行せずに保存されたチェックポイント結果が使用されて、完了したオペレーションがスキップされます。SDK によって決定的な再生が実現されます。入力およびチェックポイントログが同じであることを前提として、関数で同じ結果が生成されます。

**状態の分離:** SDK により、ビジネスロジックとは別に実行状態が維持されます。耐久性のある各実行には、他の実行ではアクセスできない独自のチェックポイントログがあります。SDK によって保管中のチェックポイントデータが暗号化され、再生間で状態の一貫性が維持されます。

## チェックポイントの仕組み
<a name="durable-sdk-how-checkpointing-works"></a>

耐久性のあるオペレーションを呼び出すと、SDK は次のシーケンスに従います。

1. **既存のチェックポイントの確認:** SDK により、このオペレーションは以前の呼び出しで既に完了されているかどうか確認されます。チェックポイントが存在する場合、SDK によってオペレーションが再実行されずに保存された結果が返されます。

1. **オペレーションを実行する:** チェックポイントが存在しない場合、SDK によってオペレーションコードが実行されます。ステップの場合、関数を呼び出すことを意味します。待機の場合、再開のスケジューリングを意味します。

1. **チェックポイントの作成:** オペレーションが完了すると、SDK によって結果がシリアル化されてチェックポイントが作成されます。チェックポイントにはオペレーションタイプ、名前、入力、結果、タイムスタンプが含まれます。

1. **チェックポイントの永続化:** SDK によって Lambda チェックポイント API が呼び出され、チェックポイントが永続化されます。実行を続行する前にチェックポイントの耐久性が実現されます。

1. **結果を返す:** SDK によってオペレーション結果がコードに返され、次のオペレーションに進みます。

このシーケンスにより、オペレーションが完了したら結果は安全に保存されます。関数がある時点で中断された場合、SDK によって最後に完了されたチェックポイントまで再生することができます。

## 再生動作
<a name="durable-sdk-replay-behavior"></a>

一時停止または中断後に関数が再開されると、SDK によって再生が実行されます。

1. **チェックポイントログの読み込み:** SDK により、この実行のチェックポイントログは Lambda から取得されます。

1. **最初から実行:** 一時停止した時点からではなく、SDK によって最初からハンドラー関数が呼び出されます。

1. **完了した耐久性のあるオペレーションのスキップ:** コードが耐久性のあるオペレーションを呼び出すと、SDK によってチェックポイントログが照合され、それぞれ確認されます。完了した耐久性のあるオペレーションには、SDK によってオペレーションコードが実行されずに保存された結果が返されます。
**注記**  
子コンテキストの結果がチェックポイントの最大サイズ (256 KB) より大きい場合、再生中にコンテキストのコードが再度実行されます。コンテキスト内で実行された耐久性のあるオペレーションで大規模な結果を構築できます。コンテキストはチェックポイントログから検索されます。したがって、コンテキスト自体で決定的コードのみを実行することが不可欠です。大規模な結果を伴う子コンテキストを使用するとき、ステップ内で長時間の作業または非決定的な作業を実行し、コンテキスト自体に結果を組み合わせた短時間実行のタスクのみを実行することがベストプラクティスです。

1. **中断ポイントでの再開:** SDK がチェックポイントなしでオペレーションに到達すると、正常に実行されて、耐久性のあるオペレーションが完了すると新しいチェックポイントが作成されます。

この再生メカニズムでは、コードが決定的である必要があります。同じ入力およびチェックポイントログの場合、関数は耐久性のあるオペレーションの呼び出しを同じシーケンスで実行する必要があります。SDK によってリプレイ中にオペレーション名およびタイプがチェックポイントログと一致することが確認されることで、これが実施されます。

## 利用可能な耐久性のあるオペレーション
<a name="durable-sdk-operations"></a>

`DurableContext` は、さまざまな調整パターンのオペレーションを提供します。耐久性のある各オペレーションによってチェックポイントが自動的に作成され、関数はどの時点からでも再開できます。

### Steps
<a name="durable-sdk-op-step"></a>

自動チェックポイントおよび再試行によってビジネスロジックが実行されます。外部サービスを呼び出したり、計算を実行したり、チェックポイントする必要があるロジックを実行したりするオペレーションのステップを使用します。SDK によってステップの前後にチェックポイントが作成され、結果が再生用に保存されます。

------
#### [ TypeScript ]

```
const result = await context.step('process-payment', async () => {
  return await paymentService.charge(amount);
});
```

------
#### [ Python ]

```
result = context.step(
    lambda _: payment_service.charge(amount),
    name='process-payment'
)
```

------
#### [ Java (Preview) ]

```
var result = context.step("process-payment", Payment.class, 
    () -> paymentService.charge(amount)
);
```

------

ステップには、設定可能な再試行戦略、実行セマンティクス (at-most-once または at-least-once)、カスタムシリアル化がサポートされます。

### 待機
<a name="durable-sdk-op-wait"></a>

コンピューティングリソースを消費せずに、指定された期間に実行が一時停止されます。SDK によってチェックポイントが作成され、関数の呼び出しが終了され、再開がスケジューリングされます。待機が完了すると Lambda によって関数が再度呼び出され、SDK によって続行される前に待機ポイントまで再生されます。

------
#### [ TypeScript ]

```
// Wait 1 hour without charges
await context.wait({ seconds: 3600 });
```

------
#### [ Python ]

```
# Wait 1 hour without charges
context.wait(3600)
```

------
#### [ Java (Preview) ]

```
// Wait 1 hour without charges
context.wait(Duration.ofHours(1));
```

------

### コールバック
<a name="durable-sdk-op-callback"></a>

コールバックにより、関数は一時停止して外部システムが入力するまで待つことができます。コールバックを作成すると、SDK によって一意のコールバック ID が生成され、チェックポイントが作成されます。その後、関数はコンピューティング料金を発生させずに停止 (呼び出しを終了する) します。外部システムは `SendDurableExecutionCallbackSuccess` または `SendDurableExecutionCallbackFailure` Lambda API を使用し、コールバック結果を送信します。コールバックが送信されると、Lambda は関数を再度呼び出します。SDK によってコールバックポイントまで再生され、関数によってコールバック結果が継続されます。

SDK には、コールバックを操作する 2 つの方法があります。

**createCallback:** コールバックが作成され、約束およびコールバック ID の両方が返されます。コールバック ID を外部システムに送信し、Lambda API を使用して結果が送信されます。

------
#### [ TypeScript ]

```
const [promise, callbackId] = await context.createCallback('approval', {
  timeout: { hours: 24 }
});

await sendApprovalRequest(callbackId, requestData);
const approval = await promise;
```

------
#### [ Python ]

```
callback = context.create_callback(
    name='approval',
    config=CallbackConfig(timeout_seconds=86400)
)

context.step(
    lambda _: send_approval_request(callback.callback_id),
    name='send_request'
)

approval = callback.result()
```

------
#### [ Java (Preview) ]

```
var config = CallbackConfig.builder(Duration.ofHours(24)).timeout()

var callback = context.createCallback("approval", String.class, config);

context.step("send-request", String.class, () -> {
    notificationService.sendApprovalRequest(callback.callbackId(), requestData);
    return "request-sent";
});

// Blocks until the callback finishes or times out
String approval = callback.get();
```

------

**waitForCallback:** コールバックの作成および送信を 1 回のオペレーションに組み合わせることで、コールバック処理が簡素化されます。SDK によってコールバックが作成され、コールバック ID で送信者関数が実行されて結果を待機します。

------
#### [ TypeScript ]

```
const result = await context.waitForCallback(
  'external-api',
  async (callbackId, ctx) => {
    await submitToExternalAPI(callbackId, requestData);
  },
  { timeout: { minutes: 30 } }
);
```

------
#### [ Python ]

```
result = context.wait_for_callback(
    lambda callback_id: submit_to_external_api(callback_id, request_data),
    name='external-api',
    config=WaitForCallbackConfig(timeout_seconds=1800)
)
```

------
#### [ Java (Preview) ]

waitForCallback 機能の Java サポートは、現在開発中です。

------

関数が無期限に待機しないようにタイムアウトを設定します。コールバックがタイムアウトした場合、SDK によって `CallbackError` がスローされ、関数はタイムアウトケースを処理できます。長時間のコールバックにハートビートタイムアウトが使用され、外部システムの応答が停止したタイミングが検出されます。

コールバックはヒューマンインザループのワークフロー、外部システム統合、ウェブフックのレスポンス、外部入力のために実行を一時停止する必要があるシナリオに使用します。

### 同時実行
<a name="durable-sdk-op-parallel"></a>

複数のオペレーションは、オプションの同時実行制御と同時に実行します。SDK によって並列実行が管理され、オペレーションごとにチェックポイントが作成されて、完了ポリシーに従って障害が処理されます。

------
#### [ TypeScript ]

```
const results = await context.parallel([
  async (ctx) => ctx.step('task1', async () => processTask1()),
  async (ctx) => ctx.step('task2', async () => processTask2()),
  async (ctx) => ctx.step('task3', async () => processTask3())
]);
```

------
#### [ Python ]

```
results = context.parallel(
    lambda ctx: ctx.step(lambda _: process_task1(), name='task1'),
    lambda ctx: ctx.step(lambda _: process_task2(), name='task2'),
    lambda ctx: ctx.step(lambda _: process_task3(), name='task3')
)
```

------
#### [ Java (Preview) ]

Parallel 機能の Java サポートは、現在開発中です。

------

`parallel` を使用して、独立したオペレーションを同時に実行します。

### マッピング
<a name="durable-sdk-op-map"></a>

オプションの同時実行制御を使用して、配列の各項目に対してオペレーションを同時に実行します。SDK によって同時実行が管理され、オペレーションごとにチェックポイントが作成されて、完了ポリシーに従って障害が処理されます。

------
#### [ TypeScript ]

```
const results = await context.map(itemArray, async (ctx, item, index) =>
  ctx.step('task', async () => processItem(item, index))
);
```

------
#### [ Python ]

```
results = context.map(
    item_array,
    lambda ctx, item, index: ctx.step(
        lambda _: process_item(item, index),
        name='task'
    )
)
```

------
#### [ Java (Preview) ]

Map 機能の Java サポートは、現在開発中です。

------

`map` を使用して同時実行制御で配列を処理します。

### 子コンテキスト
<a name="durable-sdk-op-child-context"></a>

グループ化オペレーションの分離された実行コンテキストが作成されます。子コンテキストには独自のチェックポイントログがあり、複数のステップ、待機、その他のオペレーションが含める場合があります。SDK により、子コンテキスト全体が再試行および復旧の単一ユニットとして扱われます。

子コンテキストを使用して複雑なワークフローを整理したり、サブワークフローを実装したり、まとめて再試行するオペレーションを分離したりします。

------
#### [ TypeScript ]

```
const result = await context.runInChildContext(
  'batch-processing',
  async (childCtx) => {
    return await processBatch(childCtx, items);
  }
);
```

------
#### [ Python ]

```
result = context.run_in_child_context(
    lambda child_ctx: process_batch(child_ctx, items),
    name='batch-processing'
)
```

------
#### [ Java (Preview) ]

```
var result = context.runInChildContext(
    "batch-processing", 
    String.class, 
    childCtx -> process_batch(childCtx, items)
);
```

------

再生メカニズムでは、耐久性のあるオペレーションが決定的な順序で実行されることが求められます。複数の子コンテキストを使用すると、複数の作業ストリームを同時に実行することができ、決定論は各コンテキスト内で個別に適用されます。複数の CPU コアを効率的に利用する高性能な関数を構築できます。

例えば、A および B という 2 つの子コンテキストを起動することを想定します。最初の呼び出しでは、コンテキスト内のステップは次の順序で実行され、「A」ステップは「B」ステップと同時に実行されます (A1、B1、B2、A2、A3)。再生すると、結果はチェックポイントログから取得されて、ステップが異なる順序 (B1、A1、A2、B2、A3) で発生するため、タイミングが大幅に速くなります。「A」ステップは正しい順序 (A1、A2、A3) で発生し、「B」ステップは正しい順序 (B1、B2) で発生したため、決定論の必要性は正しく満たされました。

### 条件付き待機
<a name="durable-sdk-op-wait-condition"></a>

試行間に自動チェックポイントを適用した条件によるポーリング。SDK によってチェック関数が実行され、結果を含むチェックポイントが作成されて、戦略に従って待機して条件が満たされるまで繰り返されます。

------
#### [ TypeScript ]

```
const result = await context.waitForCondition(
  async (state, ctx) => {
    const status = await checkJobStatus(state.jobId);
    return { ...state, status };
  },
  {
    initialState: { jobId: 'job-123', status: 'pending' },
    waitStrategy: (state) => 
      state.status === 'completed' 
        ? { shouldContinue: false }
        : { shouldContinue: true, delay: { seconds: 30 } }
  }
);
```

------
#### [ Python ]

```
result = context.wait_for_condition(
    lambda state, ctx: check_job_status(state['jobId']),
    config=WaitForConditionConfig(
        initial_state={'jobId': 'job-123', 'status': 'pending'},
        wait_strategy=lambda state, attempt: 
            {'should_continue': False} if state['status'] == 'completed'
            else {'should_continue': True, 'delay': 30}
    )
)
```

------
#### [ Java (Preview) ]

waitForCondition 機能の Java サポートは、現在開発中です。

------

外部システムのポーリング、リソース準備の待機、バックオフによる再試行の実装に `waitForCondition` を使用します。

### 関数の呼び出し
<a name="durable-sdk-op-invoke"></a>

別の Lambda 関数を呼び出して、結果を待機します。SDK によってチェックポイントが作成され、ターゲット関数が呼び出され、呼び出しが完了すると関数が再開されます。関数の構成およびワークフローの分解を実現します。

------
#### [ TypeScript ]

```
const result = await context.invoke(
  'invoke-processor',
  'arn:aws:lambda:us-east-1:123456789012:function:processor:1',
  { data: inputData }
);
```

------
#### [ Python ]

```
result = context.invoke(
    'arn:aws:lambda:us-east-1:123456789012:function:processor:1',
    {'data': input_data},
    name='invoke-processor'
)
```

------
#### [ Java (Preview) ]

```
var result = context.invoke(
    "invoke-processor", 
    "arn:aws:lambda:us-east-1:123456789012:function:processor:1",
    inputData,
    Result.class, 
    InvokeConfig.builder().build()
);
```

------

## 耐久性のあるオペレーションの計測方法
<a name="durable-operations-checkpoint-consumption"></a>

`DurableContext` を通じて呼び出す耐久性のあるすべてのオペレーションによってチェックポイントが作成され、実行の進行状況が追跡されて状態データが保存されます。これらのオペレーションは使用状況に基づいて料金が発生し、チェックポイントにはデータの書き込みおよび保持コストに寄与するデータが含まれる場合があります。保存データには、呼び出しイベントデータ、ステップから返されたペイロード、コールバックの完了時に渡されたデータが含まれます。耐久性のあるオペレーションの計測方法を理解することで、実行コストを見積もってワークフローを最適化できます。料金の詳細については、「[Lambda の料金ページ](https://aws.amazon.com/lambda/pricing/)」を参照してください。

ペイロードサイズとは、耐久性のあるオペレーションが保持されるシリアル化されたデータのサイズを指します。データはバイト単位で測定され、サイズはオペレーションで使用されるシリアライザーによって異なります。オペレーションのペイロードは、正常な完了による結果自体であるか、オペレーションが失敗した場合はシリアル化されたエラーオブジェクトの可能性があります。

### 基本的なオペレーション
<a name="durable-operations-basic"></a>

基本的なオペレーションは、耐久性のある関数の基礎的な構成要素です。


| 運用 | チェックポイントのタイミング | オペレーション数 | 継続したデータ | 
| --- | --- | --- | --- | 
| 実行 | 起動済み | 1 | 入力ペイロードのサイズ | 
| 実行 | 完了 (成功/失敗/停止) | 0 | 出力ペイロードのサイズ | 
| [ステップ] | 再試行/成功/失敗 | 1 \$1 N 回の再試行 | 各試行から返されるペイロードのサイズ | 
| 待機 | 起動済み | 1 | 該当なし | 
| WaitForCondition | 各ポーリング試行 | 1 \$1 N ポーリング | 各ポーリング試行から返されるペイロードサイズ | 
| 呼び出しレベルの再試行 | 起動済み | 1 | エラーオブジェクトのペイロード | 

### コールバックオペレーション
<a name="durable-operations-callbacks"></a>

コールバックオペレーションは、関数が一時停止して外部システムが入力するまで待てるようにします。これらのオペレーションは、コールバックの作成時および完了時にチェックポイントを作成します。


| 運用 | チェックポイントのタイミング | オペレーション数 | 継続したデータ | 
| --- | --- | --- | --- | 
| CreateCallback | 起動済み | 1 | 該当なし | 
| API コールによるコールバック完了 | 完了 | 0 | コールバックペイロード | 
| WaitForCallback | 起動済み | 3 \$1 N 回の再試行 (コンテキスト \$1 コールバック \$1 ステップ) | 送信者ステップの試行によって返されるペイロード、ならびにコールバックペイロードの 2 つのコピー | 

### 複合オペレーション
<a name="durable-operations-compound"></a>

複合オペレーションでは複数の耐久性のあるオペレーションを組み合わせて、並列実行、配列処理、ネストされたコンテキストなどの複雑な調整パターンが処理されます。


| 運用 | チェックポイントのタイミング | オペレーション数 | 継続したデータ | 
| --- | --- | --- | --- | 
| 並行 | 起動済み | 1 \$1 N ブランチ (1 親コンテキスト \$1 N 子コンテキスト) | 各ブランチから返されたペイロードサイズの最大 2 コピー、ならびに各ブランチのステータス | 
| マッピング | 起動済み | 1 \$1 N ブランチ (1 親コンテキスト \$1 N 子コンテキスト) | 各イテレーションから返されたペイロードサイズの最大 2 コピー、ならびに各イテレーションのステータス | 
| 約束ヘルパー | 完了 | 1 | 約束から返されたペイロードサイズ | 
| RunInChildContext | 成功/失敗 | 1 | 子コンテキストから返されるペイロードサイズ | 

`runInChildContext` から、または複合オペレーションによって内部的に使用されるコンテキストなどの場合、256 KB 未満の結果は直接チェックポイントされます。大規模な結果は保存されずに、コンテキストのオペレーションが再処理されることでリプレイ中に再構築されます。

# 耐久関数のサポートされているランタイム
<a name="durable-supported-runtimes"></a>

耐久性のある関数は、ランタイムバージョンの柔軟性を高めるために、選択したマネージドランタイムと OCI コンテナイメージで使用できます。Node.js および Python の耐久性のある関数は、マネージドランタイムを使用してコンソールで直接作成するか、infrastructure-as-code を使用してプログラムで作成できます。Java 版の耐久性のある関数は現在プレビュー中のため、デプロイにはコンテナイメージを使用する必要があります。

## Lambda マネージドランタイム
<a name="durable-managed-runtimes"></a>

Lambda コンソールで関数を作成する場合、または AWS CLI で `--durable-config '{"ExecutionTimeout": 3600, "RetentionPeriodInDays": 7}'` パラメータを指定して関数を作成する場合、以下のマネージドランタイムが耐久関数をサポートします。Lambda ランタイムの詳細については、「[Lambda ランタイム](lambda-runtimes.md)」を参照してください。


| Language | ランタイム | 
| --- | --- | 
| Node.js | nodejs22.x | 
| Node.js | nodejs24.x | 
| Python | python3.13 | 
| Python | python3.14 | 

**注記**  
Lambda ランタイムには、テストおよび開発用の耐久性のある実行 SDK が含まれています。ただし、本番稼働用のデプロイパッケージに SDK を含めることをお勧めします。これにより、バージョンの一貫性が確保され、関数の動作に影響を与える可能性のあるランタイム更新を回避できます。

### Node.js
<a name="durable-runtime-nodejs"></a>

Node.js プロジェクトに SDK をインストールする:

```
npm install @aws/durable-execution-sdk-js
```

SDK は JavaScript と TypeScript をサポートしています。TypeScript プロジェクトの場合、SDK にはタイプ定義が含まれます。

### Python
<a name="durable-runtime-python"></a>

Python プロジェクトに SDK をインストールする:

```
pip install aws-durable-execution-sdk-python
```

Python SDK は同期メソッドを使用し、`async/await` は必要ありません。

### Java (プレビュー)
<a name="durable-runtime-java"></a>

依存関係を `pom.xml` に追加する:

```
<dependency>
    <groupId>software.amazon.lambda.durable</groupId>
    <artifactId>aws-durable-execution-sdk-java</artifactId>
    <version>VERSION</version>
</dependency>
```

Java プロジェクトに SDK をインストールする:

```
mvn install
```

Java SDK のプレビュー版が利用可能です。waitForCondition、waitForCallback、並列およびマップオペレーションはまだ開発中です。

## コンテナイメージ
<a name="durable-container-images"></a>

コンテナイメージで耐久関数を使用して、追加のランタイムバージョンまたはカスタムランタイム設定をサポートできます。コンテナイメージを使用すると、マネージドランタイムとして使用できないランタイムバージョンを使用したり、ランタイム環境をカスタマイズしたりできます。

コンテナイメージを使用した耐久関数を作成するには:

1. Lambda ベースイメージに基づいて Dockerfile を作成する

1. コンテナに耐久性のある実行 SDK をインストールする

1. コンテナイメージを構築して Amazon Elastic Container Registry にプッシュする

1. 耐久性のある実行を有効にしたコンテナイメージから Lambda 関数を作成する

### コンテナの例
<a name="durable-container-python"></a>

Dockerfile を作成する:

------
#### [ Python ]

Python 3.11 用の Dockerfile を作成する:

```
FROM public.ecr.aws/lambda/python:3.11

# Copy requirements file
COPY requirements.txt ${LAMBDA_TASK_ROOT}/

# Install dependencies including durable SDK
RUN pip install -r requirements.txt

# Copy function code
COPY lambda_function.py ${LAMBDA_TASK_ROOT}/

# Set the handler
CMD [ "lambda_function.handler" ]
```

`requirements.txt` ファイルを作成する:

```
aws-durable-execution-sdk-python
```

------
#### [ Java (Preview) ]

Java 25 用の Dockerfile を作成する:

```
FROM --platform=linux/amd64 public.ecr.aws/lambda/java:25

# Install Maven
RUN dnf install -y maven

WORKDIR /var/task

# Copy Maven configuration and source code
COPY pom.xml .
COPY src ./src

# Build
RUN mvn clean package -DskipTests

# Move JAR to lib directory
RUN mv target/*.jar lib/

# Set the handler
CMD ["src.path.to.lambdaFunction::handler"]
```

------

Docker イメージをビルドおよびプッシュする:

```
# Build the image
docker build -t my-durable-function .

# Tag for ECR
docker tag my-durable-function:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-durable-function:latest

# Push to ECR
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-durable-function:latest
```

耐久性のある実行を有効にして関数を作成します。

```
aws lambda create-function \
  --function-name myDurableFunction \
  --package-type Image \
  --code ImageUri=123456789012.dkr.ecr.us-east-1.amazonaws.com/my-durable-function:latest \
  --role arn:aws:iam::123456789012:role/lambda-execution-role \
  --durable-config '{"ExecutionTimeout": 3600, "RetentionPeriodInDays": 7}'
```

Lambda によるコンテナイメージの使用に関する詳細については、「Lambda デベロッパーガイド」の「[コンテナイメージを使用した Lambda 関数の作成](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html)」を参照してください。

## ランタイムの考慮事項
<a name="durable-runtime-considerations"></a>

**SDK バージョン管理:** デプロイパッケージまたはコンテナイメージに耐久性のある実行 SDK が含まれます。これにより、関数が特定の SDK バージョンを使用し、ランタイム更新の影響を受けなくなります。`package.json` または `requirements.txt` で SDK バージョンをピン留めして、アップグレード時に制御します。

**ランタイムの更新:** AWS はマネージドランタイムを更新して、セキュリティパッチとバグ修正を含めます。これらの更新には、新しい SDK バージョンが含まれる場合があります。予期しない動作を回避するには、SDK をデプロイパッケージに含め、本番環境にデプロイする前に徹底的にテストします。

**コンテナイメージサイズ:** コンテナイメージの最大非圧縮サイズは 10 GB です。耐久性のある実行 SDK は、イメージに最小サイズを追加します。多段式ビルドを使用し、不要な依存関係を削除して、コンテナを最適化します。

**コールドスタートの性能:** コンテナイメージは、マネージドランタイムよりもコールドスタート時間が長くなる場合があります。耐久性のある実行 SDK を使用しても、コールドスタート性能への影響をほとんどありません。アプリケーションにとってコールドスタートレイテンシーが重要な場合は、プロビジョニングされた同時実行を使用します。

# 耐久性のある Lambda 関数の呼び出し
<a name="durable-invoking"></a>

耐久性のある Lambda 関数では、標準の Lambda 関数と同じ呼び出し方法がサポートされます。耐久性のある関数は同期的に、非同期的に、イベントソースマッピングを通じて呼び出すことができます。呼び出しプロセスは標準関数と同じですが、耐久性のある関数は長時間の実行および自動状態管理には追加機能を提供します。

## 呼び出し方法
<a name="durable-invoking-methods"></a>

**同期呼び出し:** 耐久性のある関数を呼び出して、レスポンスを待ちます。同期呼び出しは、Lambda によって 15 分 (設定された関数および実行タイムアウトに応じて 15 分以下) に制限されます。結果が即時に必要な場合、またはレスポンスが予想される API やサービスと統合する場合、同期呼び出しを使用します。呼び出し元を中断せず、待機オペレーションを使用して効率的な計算を行うことができます。呼び出しは耐久性のある実行全体が完了するまで待機します。べき等実行を開始するには、[べき等性](durable-execution-idempotency.md)の説明に従って実行名パラメータを使用してください。

```
aws lambda invoke \
  --function-name my-durable-function:1 \
  --cli-binary-format raw-in-base64-out \
  --payload '{"orderId": "12345"}' \
  response.json
```

**非同期呼び出し:** レスポンスを待たずに処理するイベントをキューに入れます。Lambda によってイベントがキューに配置されて、すぐに返されます。非同期呼び出しは最大 1 年間の実行期間をサポートします。非同期呼び出しは「fire-and-forget」シナリオに使用するか、バックグラウンドで処理が発生する可能性がある場合に使用します。べき等実行を開始するには、[べき等性](durable-execution-idempotency.md)の説明に従って実行名パラメータを使用してください。

```
aws lambda invoke \
  --function-name my-durable-function:1 \
  --invocation-type Event \
  --cli-binary-format raw-in-base64-out \
  --payload '{"orderId": "12345"}' \
  response.json
```

**イベントソースマッピング:** Amazon SQS、Kinesis、DynamoDB などのストリームまたはキューベースのサービスでレコードが利用可能な場合、耐久性のある関数を自動的に呼び出すように Lambda を設定します。イベントソースマッピングではイベントソースがポーリングされ、レコードのバッチで関数が呼び出されます。実行期間の制限を含め、耐久性のある関数でイベントソースマッピングの使用に関する詳細については、「[耐久性のある関数でイベントソースマッピング](durable-invoking-esm.md)」を参照してください。

各呼び出し方法の詳細については、「[同期呼び出し](invocation-sync.md)」および「[非同期呼び出し](invocation-async.md)」を参照してください。

**注記**  
耐久性のある関数では、エラー処理用のデッドレターキュー (DLQ) がサポートされていますが、Lambda 送信先はサポートされていません。DLQ を設定し、失敗した呼び出しのレコードをキャプチャします。

## 修飾 ARN の要件
<a name="durable-invoking-qualified-arns"></a>

耐久性のある関数には、呼び出しをするために修飾識別子が必要です。バージョン番号、エイリアス、`$LATEST` を使用して耐久性のある関数を呼び出す必要があります。完全修飾 ARN またはバージョン/エイリアスサフィックス付きの関数名のいずれかを使用できます。非修飾識別子 (バージョンまたはエイリアスサフィックスなし) を使用することはできません。

**有効な呼び出し:**

```
# Using full ARN with version number
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1

# Using full ARN with alias
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:prod

# Using full ARN with $LATEST
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:$LATEST

# Using function name with version number
my-durable-function:1

# Using function name with alias
my-durable-function:prod
```

**無効な呼び出し:**

```
# Unqualified ARN (not allowed)
arn:aws:lambda:us-east-1:123456789012:function:my-durable-function

# Unqualified function name (not allowed)
my-durable-function
```

この要件により、耐久性のある実行がライフサイクル中に一貫性が維持されます。耐久性のある実行が開始されると、特定の関数バージョンに固定されます。関数が数時間後または数日後に一時停止して再開した場合、Lambda によって実行を開始したバージョンが呼び出され、ワークフロー全体でコードの一貫性が確保されます。

**ベストプラクティス**  
`$LATEST` ではなく、本番稼働の耐久性のある関数には番号付きのバージョンまたはエイリアスを使用します。番号付きバージョンは不変で、確定的な再生をサポートします。オプションとして、エイリアスは更新できる安定したリファレンスを提供し、呼び出しコードを変更せずに新しいバージョンを指します。エイリアスを更新すると、新しい実行では新しいバージョンが使用されますが、進行中の実行では元のバージョンが継続されます。`$LATEST` を使用してプロトタイプを作成するか、開発中のデプロイ時間を短縮することができます。実行中に基盤となるコードが変更された場合、実行が正しく再生されない (または失敗する) 可能性があることを理解してください。

## 実行ライフサイクルの概要
<a name="durable-invoking-execution-lifecycle"></a>

耐久性のある関数を呼び出すと、Lambda は複数の関数の呼び出しをまたぐ耐久性のある実行を作成します。

1. **初期呼び出し:** 呼び出しリクエストにより、新しい耐久性のある実行が作成されます。Lambda によって一意の実行 ID が割り当てられて、処理が開始されます。

1. **実行とチェックポイント:** 関数が耐久性のあるオペレーションを実行すると、SDK によって進行状況が追跡されるチェックポイントが作成されます。

1. **停止 (必要な場合):** 関数が `wait` や `waitForCallback` などの耐久性のある待機を使用した場合、または自動ステップ再試行を使用した場合、Lambda は実行を停止してコンピューティング時間の課金を停止します。

1. **再開:** 再開するとき (再試行後を含む)、Lambda によって関数が再度呼び出されます。SDK によってチェックポイントログが再生され、実行が一時停止した時点から続行されます。

1. **完了:** 関数が最終結果を返すか、未処理のエラーをスローすると、耐久性のある実行が完了します。

同期呼び出しの場合、呼び出し元は、耐久性のある実行全体が完了するまで待機します (待機操作を含む)。実行が呼び出しタイムアウト (15 分以下) を超えた場合、呼び出しはタイムアウトします。非同期呼び出しの場合、Lambda はすぐに返して実行は独立して続行されます。耐久性のある実行 API を使用して実行ステータスを追跡し、最終結果を取得します。

## アプリケーションコードからの呼び出し
<a name="durable-invoking-with-sdk"></a>

AWS SDK を使用して、アプリケーションコードから耐久性のある関数を呼び出します。呼び出しプロセスは標準関数と同じです。

------
#### [ TypeScript ]

```
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';

const client = new LambdaClient({});

// Synchronous invocation
const response = await client.send(new InvokeCommand({
  FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
  Payload: JSON.stringify({ orderId: '12345' })
}));

const result = JSON.parse(Buffer.from(response.Payload!).toString());

// Asynchronous invocation
await client.send(new InvokeCommand({
  FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
  InvocationType: 'Event',
  Payload: JSON.stringify({ orderId: '12345' })
}));
```

------
#### [ Python ]

```
import boto3
import json

client = boto3.client('lambda')

# Synchronous invocation
response = client.invoke(
    FunctionName='arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
    Payload=json.dumps({'orderId': '12345'})
)

result = json.loads(response['Payload'].read())

# Asynchronous invocation
client.invoke(
    FunctionName='arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
    InvocationType='Event',
    Payload=json.dumps({'orderId': '12345'})
)
```

------

## 連鎖呼び出し
<a name="durable-invoking-chained"></a>

耐久性のある関数によって `DurableContext` からの `invoke`オペレーションが使用されて、他の耐久性のある関数および耐久性のない関数を呼び出すことができます。呼び出される関数が完了するまで、呼び出し元の関数が待機 (一時停止) する連鎖呼び出しが作成されます。

------
#### [ TypeScript ]

```
export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Invoke another durable function and wait for result
    const result = await context.invoke(
      'process-order',
      'arn:aws:lambda:us-east-1:123456789012:function:order-processor:1',
      { orderId: event.orderId }
    );
    
    return { statusCode: 200, body: JSON.stringify(result) };
  }
);
```

------
#### [ Python ]

```
@durable_execution
def handler(event, context: DurableContext):
    # Invoke another durable function and wait for result
    result = context.invoke(
        'arn:aws:lambda:us-east-1:123456789012:function:order-processor:1',
        {'orderId': event['orderId']},
        name='process-order'
    )
    
    return {'statusCode': 200, 'body': json.dumps(result)}
```

------

連鎖呼び出しは、呼び出し元の関数にチェックポイントを作成します。呼び出し元の関数が中断された場合、関数を再呼び出しせずに、呼び出される関数の結果でチェックポイントから再開されます。

**注記**  
クロスアカウントの連鎖呼び出しはサポートされていません。呼び出される関数は、呼び出し元の関数と同じ AWS アカウントに存在する必要があります。

# 耐久関数を使用したイベントソースマッピング
<a name="durable-invoking-esm"></a>

耐久関数は、すべての Lambda イベントソースマッピングで機能します。耐久関数のイベントソースマッピングは、標準関数の設定と同じ方法で設定します。イベントソースマッピングは、Amazon SQS、Kinesis、DynamoDB Streams などのイベントソースを自動的にポーリングし、レコードのバッチで関数を呼び出します。

イベントソースマッピングは、複雑なマルチステップワークフローでストリームまたはキューを処理する耐久関数に有用です。例えば、再試行、外部 API コール、人間の承認を使用して Amazon SQS メッセージを処理する耐久関数を作成できます。

## イベントソースマッピングが耐久関数を呼び出す方法
<a name="durable-esm-invocation-behavior"></a>

イベントソースマッピングは、耐久関数を同期的に呼び出し、耐久性のある実行が完全に終了するのを待ってから、次のバッチを処理したり、レコードを処理済みとしてマークします。耐久性のある実行の合計時間が 15 分を超えると、実行はタイムアウトして失敗します。イベントソースマッピングはタイムアウト例外を受け取り、再試行設定に従って処理します。

## 15 分間の実行制限
<a name="durable-esm-duration-limit"></a>

耐久関数がイベントソースマッピングによって呼び出される場合、耐久性のある実行の合計時間は 15 分を超えることはできません。この制限は、個々の関数呼び出しだけでなく、最初から最後までの耐久性のある実行全体に適用されます。

この 15 分の制限は、Lambda 関数のタイムアウト (最大 15 分) とは別です。関数タイムアウトは、個々の呼び出しを実行できる時間を制御し、耐久性のある実行のタイムアウトは、実行開始から完了までの合計経過時間を制御します。

**シナリオ例:**
+ **有効:** 耐久関数は、Amazon SQS メッセージを 3 つのステップで処理します。各ステップには 2 分かかり、最後のステップを完了するまで 5 分待機します。合計実行時間: 11 分。これは、合計が 15 分未満であるために機能します。
+ **無効:** 耐久関数は Amazon SQS メッセージを処理し、最初の処理を 2 分で完了してから、外部コールバックが完了するまで 20 分待機します。合計実行時間: 22 分。これは 15 分の制限を超え、失敗します。
+ **無効:** 耐久関数は、ステップ間に合計 30 分におよぶ複数の待機操作を伴いつつ、Kinesis レコードを処理します。個々の呼び出しは迅速に完了しますが、合計実行時間は 15 分を超えています。

**重要**  
イベントソースマッピングを使用する場合、耐久性のある実行のタイムアウトを 15 分以下に設定してください。そうしないと、イベントソースマッピングの作成は失敗します。ワークフローで実行時間が長い場合は、以下で説明する中間関数パターンを使用します。

## イベントソースマッピングの設定
<a name="durable-esm-configuration"></a>

Lambda コンソール、AWS CLI、または AWS SDK を使用して、耐久性のある関数のイベントソースマッピングを設定します。すべての標準イベントソースマッピングのプロパティは、耐久関数に適用されます。

```
aws lambda create-event-source-mapping \
  --function-name arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1 \
  --event-source-arn arn:aws:sqs:us-east-1:123456789012:my-queue \
  --batch-size 10 \
  --maximum-batching-window-in-seconds 5
```

耐久関数のイベントソースマッピングを設定するときは、必ず修飾 ARN (バージョン番号またはエイリアス) を使用してください。

## イベントソースマッピングによるエラー処理
<a name="durable-esm-error-handling"></a>

イベントソースマッピングは、耐久関数で動作する組み込みのエラー処理を提供します。
+ **再試行動作:** 最初の呼び出しが失敗した場合、イベントソースマッピングは再試行設定に従って再試行します。要件に基づいて最大再試行回数と再試行間隔を設定します。
+ **デッドレターキュー: **すべての再試行後に失敗したレコードをキャプチャするようにデッドレター キューを構成します。これにより、メッセージの損失を防ぎ、失敗したレコードを手動で検査できます。
+ **部分的なバッチ処理の失敗:** Amazon SQS および Kinesis では、部分的なバッチ処理の失敗レポートを使用して、レコードを個別に処理し、失敗したレコードのみを再試行します。
+ **Bisect on error:** Kinesis および DynamoDB Streams の場合、bisect on error 機能を有効にして、失敗したバッチを分割し、問題のあるレコードを分離します。

**注記**  
耐久性のある関数では、エラー処理用のデッドレターキュー (DLQ) がサポートされていますが、Lambda 送信先はサポートされていません。DLQ を設定し、失敗した呼び出しのレコードをキャプチャします。

イベントソースマッピングエラー処理の詳細については、[「イベントソースマッピング](invocation-eventsourcemapping.md)」を参照してください。

## 長時間実行されるワークフローに中間関数を使用する
<a name="durable-esm-intermediary-function"></a>

ワークフローの完了に 15 分以上かかる場合は、イベントソースマッピングと耐久関数の間に中間標準 Lambda 関数を使用します。中間関数は、イベントソースマッピングからイベントを受信し、耐久関数を非同期的に呼び出し、15 分間の実行制限を削除します。

このパターンは、イベントソースマッピングの同期呼び出しモデルを耐久関数の長時間かかる実行モデルから切り離します。イベントソースマッピングは中間関数を呼び出し、中間関数は耐久性のある実行を開始した後すぐに返されます。その後、耐久関数は、必要な期間 (最大 1 年間) 独立して実行されます。

### アーキテクチャ
<a name="durable-esm-intermediary-architecture"></a>

中間関数パターンでは、次の 3 つのコンポーネントを使用します。

1. **イベントソースマッピング:** イベントソース (Amazon SQS、Kinesis、DynamoDB Streams) をポーリングし、レコードのバッチと同期的に中間関数を呼び出します。

1. **中間関数:** イベントソースマッピングからイベントを受信し、必要に応じてデータを検証および変換し、耐久関数を非同期的に呼び出す標準の Lambda 関数。この関数は迅速に (通常は 1 秒未満) 完了し、イベントソースマッピングに制御を返します。

1. **耐久関数:** 長時間の実行が可能な複雑かつ多段階のロジックでイベントを処理します。非同期的に呼び出されるため、15 分の制限による制約はありません。

### 実装
<a name="durable-esm-intermediary-implementation"></a>

中間関数は、イベントソースマッピングからイベント全体を受信し、耐久関数を非同期的に呼び出します。実行名パラメータを使用してべき等実行が開始されるようにし、イベントソースマッピングが再試行された場合に重複処理を防止します。

------
#### [ TypeScript ]

```
import { LambdaClient, InvokeCommand } from '@aws-sdk/client-lambda';
import { SQSEvent } from 'aws-lambda';
import { createHash } from 'crypto';

const lambda = new LambdaClient({});

export const handler = async (event: SQSEvent) => {
  // Invoke durable function asynchronously with execution name
  await lambda.send(new InvokeCommand({
    FunctionName: 'arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
    InvocationType: 'Event',
    Payload: JSON.stringify({
      executionName: event.Name,
      event: event
    })
  }));
  
  return { statusCode: 200 };
};
```

------
#### [ Python ]

```
import boto3
import json
import hashlib

lambda_client = boto3.client('lambda')

def handler(event, context):  
    # Invoke durable function asynchronously with execution name
    lambda_client.invoke(
        FunctionName='arn:aws:lambda:us-east-1:123456789012:function:my-durable-function:1',
        InvocationType='Event',
        Payload=json.dumps({
            'executionName': execution_name,
            'event': event["name"]
        })
    )
    
    return {'statusCode': 200}
```

------

中間関数自体のべき等性については、[Powertools for AWS Lambda](https://docs.aws.amazon.com//powertools/) を使用して、イベントソースマッピングが中間関数を再試行した場合に、耐久関数の重複呼び出しを防止します。

耐久関数は、実行名を持つペイロードを受信し、長時間実行されるロジックを持つすべてのレコードを処理します。

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';

export const handler = withDurableExecution(
  async (payload: any, context: DurableContext) => {
    const sqsEvent = payload.event;
    
    // Process each record with complex, multi-step logic
    const results = await context.map(
      sqsEvent.Records,
      async (ctx, record) => {
        const validated = await ctx.step('validate', async () => {
          return validateOrder(JSON.parse(record.body));
        });
        
        // Wait for external approval (could take hours or days)
        const approval = await ctx.waitForCallback(
          'approval',
          async (callbackId) => {
            await requestApproval(callbackId, validated);
          },
          { timeout: { hours: 48 } }
        );
        
        // Complete processing
        return await ctx.step('complete', async () => {
          return completeOrder(validated, approval);
        });
      }
    );
    
    return { statusCode: 200, processed: results.getResults().length };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
from aws_durable_execution_sdk_python.config import Duration, WaitForCallbackConfig
from collections.abc import Sequence
import json

def validate_order(order_data: dict) -> dict:
    """Validate order data - always passes."""
    return order_data

def request_approval(callback_id: str, validated_order: dict) -> None:
    """Request approval for the order - always passes."""
    pass

def complete_order(validated_order: dict, approval_result: str) -> dict:
    """Complete the order processing - always passes."""
    return validated_order

@durable_execution
def lambda_handler(payload, context: DurableContext):
    sqs_event = payload['event']

    def process_record(
        ctx: DurableContext, 
        record: dict, 
        index: int, 
        items: Sequence[dict]
    ) -> dict:
        validated = ctx.step(
            lambda _: validate_order(json.loads(record['body'])),
            name=f'validate-{index}'
        )

        approval = ctx.wait_for_callback(
            submitter=lambda callback_id, wait_ctx: request_approval(callback_id, validated),
            name=f'approval-{index}',
            config=WaitForCallbackConfig(timeout=Duration.from_seconds(172800))
        )

        return ctx.step(
            lambda _: complete_order(validated, approval),
            name=f'complete-{index}'
        )

    results = context.map(
        inputs=sqs_event['Records'],
        func=process_record,
        name='process-records'
    )

    return {
        'statusCode': 200, 
        'started': results.started_count,
        'completed': results.success_count,
        'failed': results.failure_count,
        'total': results.total_count
    }
```

------

### 主な考慮事項
<a name="durable-esm-intermediary-tradeoffs"></a>

このパターンは、耐久性のある実行からイベントソースマッピングを切り離すことで、15 分間の実行制限を削除します。中間関数は、耐久性のある実行を開始した直後に返り、イベントソースマッピングの処理を続行できるようにします。その後、耐久関数は、必要な期間だけ独立して実行されます。

中間関数は、耐久性のある実行が完了したときではなく、耐久関数を呼び出すときに成功します。耐久性のある実行が後で失敗した場合、イベントソースマッピングはすでにバッチを正常に処理しているため、再試行されません。耐久関数にエラー処理を実装し、失敗した実行に対してデッドレターキューを設定します。

実行名パラメータを使用して、べき等実行が開始されるようにします。イベントソースマッピングが中間関数を再試行する場合、実行名がすでに存在するため、耐久関数は重複した実行を開始しません。

## サポートされているイベントソース
<a name="durable-esm-supported-sources"></a>

耐久関数は、イベントソースマッピングを使用するすべての Lambda イベントソースをサポートします。
+ Amazon SQS キュー (スタンダードおよび FIFO)
+ Kinesis Streams
+ DynamoDB Streams
+ Amazon Managed Streaming for Apache Kafka (Amazon MSK)
+ セルフマネージド Apache Kafka
+ Amazon MQ (ActiveMQ および RabbitMQ)
+ Amazon DocumentDB 変更ストリーム

耐久関数を呼び出す場合、すべてのイベントソースタイプには 15 分間の耐久性のある実行制限が適用されます。

# Lambda の耐久関数の再試行
<a name="durable-execution-sdk-retries"></a>

耐久関数は、アプリケーションの一時的な障害に対する回復力を高める自動再試行機能を提供します。SDK は、ビジネスロジックの障害に対するステップ再試行とインフラストラクチャの障害に対するバックエンド再試行の 2 つのレベルで再試行を処理します。

## ステップの再試行
<a name="durable-step-retries"></a>

ステップ内で捕捉されなかった例外が発生すると、SDK は設定された再試行戦略に基づいてステップを自動的に再試行します。ステップの再試行は、チェックポイントされた操作であり、SDK が実行を中断しても、進行状況を失うことなく後で再開できるようにします。

### ステップの再試行動作
<a name="durable-step-retry-behavior"></a>

次の表は、SDK がステップ内で例外を処理する方法を示しています。


| シナリオ | どうなるのか | 計測への影響 | 
| --- | --- | --- | 
| 再試行回数が残っているステップにおける例外 | SDK は再試行のチェックポイントを作成し、関数を停止します。次の呼び出しで、ステップは設定されたバックオフ遅延を伴って再試行します。 | 1 回のオペレーション \$1 エラーペイロードサイズ | 
| 再試行回数が残っていないステップにおける例外 | ステップは失敗し、例外をスローします。ハンドラーコードがこの例外をキャッチしない場合、実行全体が失敗します。 | 1 回のオペレーション \$1 エラーペイロードサイズ | 

ステップを再試行する必要があるとき、SDK は再試行状態をチェックポイントし、他の作業が実行されていない場合は Lambda 呼び出しを終了します。これにより、SDK はコンピュートリソースを消費することなくバックオフ遅延を実装できます。関数はバックオフ期間の後に自動的に再開されます。

### ステップ再試行戦略の設定
<a name="durable-step-retry-configuration"></a>

再試行戦略を設定して、ステップが失敗を処理する方法を制御します。最大試行回数、バックオフ間隔、再試行条件を指定できます。

**最大試行回数付きのエクスポネンシャルバックオフ:**

------
#### [ TypeScript ]

```
const result = await context.step('call-api', async () => {
  const response = await fetch('https://api.example.com/data');
  if (!response.ok) throw new Error(`API error: ${response.status}`);
  return await response.json();
}, {
  retryStrategy: (error, attemptCount) => {
    if (attemptCount >= 5) {
      return { shouldRetry: false };
    }
    // Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s)
    const delay = Math.min(2 * Math.pow(2, attemptCount - 1), 300);
    return { shouldRetry: true, delay: { seconds: delay } };
  }
});
```

------
#### [ Python ]

```
def retry_strategy(error, attempt_count):
    if attempt_count >= 5:
        return {'should_retry': False}
    # Exponential backoff: 2s, 4s, 8s, 16s, 32s (capped at 300s)
    delay = min(2 * (2 ** (attempt_count - 1)), 300)
    return {'should_retry': True, 'delay': delay}

result = context.step(
    lambda _: call_external_api(),
    name='call-api',
    config=StepConfig(retry_strategy=retry_strategy)
)
```

------

**固定間隔バックオフ:**

------
#### [ TypeScript ]

```
const orders = await context.step('query-orders', async () => {
  return await queryDatabase(event.userId);
}, {
  retryStrategy: (error, attemptCount) => {
    if (attemptCount >= 3) {
      return { shouldRetry: false };
    }
    return { shouldRetry: true, delay: { seconds: 5 } };
  }
});
```

------
#### [ Python ]

```
def retry_strategy(error, attempt_count):
    if attempt_count >= 3:
        return {'should_retry': False}
    return {'should_retry': True, 'delay': 5}

orders = context.step(
    lambda _: query_database(event['userId']),
    name='query-orders',
    config=StepConfig(retry_strategy=retry_strategy)
)
```

------

**条件付き再試行 (特定のエラーのみを再試行):**

------
#### [ TypeScript ]

```
const result = await context.step('call-rate-limited-api', async () => {
  const response = await fetch('https://api.example.com/data');
  
  if (response.status === 429) throw new Error('RATE_LIMIT');
  if (response.status === 504) throw new Error('TIMEOUT');
  if (!response.ok) throw new Error(`API_ERROR_${response.status}`);
  
  return await response.json();
}, {
  retryStrategy: (error, attemptCount) => {
    // Only retry rate limits and timeouts
    const isRetryable = error.message === 'RATE_LIMIT' || error.message === 'TIMEOUT';
    
    if (!isRetryable || attemptCount >= 3) {
      return { shouldRetry: false };
    }
    
    // Exponential backoff: 1s, 2s, 4s (capped at 30s)
    const delay = Math.min(Math.pow(2, attemptCount - 1), 30);
    return { shouldRetry: true, delay: { seconds: delay } };
  }
});
```

------
#### [ Python ]

```
def retry_strategy(error, attempt_count):
    # Only retry rate limits and timeouts
    is_retryable = str(error) in ['RATE_LIMIT', 'TIMEOUT']
    
    if not is_retryable or attempt_count >= 3:
        return {'should_retry': False}
    
    # Exponential backoff: 1s, 2s, 4s (capped at 30s)
    delay = min(2 ** (attempt_count - 1), 30)
    return {'should_retry': True, 'delay': delay}

result = context.step(
    lambda _: call_rate_limited_api(),
    name='call-rate-limited-api',
    config=StepConfig(retry_strategy=retry_strategy)
)
```

------

**再試行を無効にする:**

------
#### [ TypeScript ]

```
const isDuplicate = await context.step('check-duplicate', async () => {
  return await checkIfOrderExists(event.orderId);
}, {
  retryStrategy: () => ({ shouldRetry: false })
});
```

------
#### [ Python ]

```
is_duplicate = context.step(
    lambda _: check_if_order_exists(event['orderId']),
    name='check-duplicate',
    config=StepConfig(
        retry_strategy=lambda error, attempt: {'should_retry': False}
    )
)
```

------

再試行戦略が `shouldRetry: false` を返すと、ステップは再試行せずにすぐに失敗します。これは、べき等性チェックや、安全に再実行できない副作用を伴う操作など、再試行すべきでない操作に使用します。

## ステップ外の例外
<a name="durable-handler-exceptions"></a>

ステップ外でハンドラーコードで捕捉されなかった例外が発生した場合、SDK は実行を失敗としてマークします。これにより、アプリケーションロジックのエラーが適切にキャプチャされ、報告されます。


| シナリオ | どうなるのか | 計測への影響 | 
| --- | --- | --- | 
| ステップ外のハンドラーコードの例外 | SDK は実行を FAILED としてマークし、エラーを返します。例外は自動的に再試行されません。 | エラーペイロードサイズ | 

エラーが発生しやすいコードの自動再試行を有効にするには、再試行戦略を使用してステップ内でラップします。ステップでは、設定可能なバックオフ付きの自動再試行が行われますが、ステップ外のコードは即座に失敗します。

## バックエンドの再試行
<a name="durable-backend-retries"></a>

バックエンドの再試行は、Lambda でインフラストラクチャの障害やランタイムエラーが発生した場合、または SDK が耐久性のある実行サービスと通信できない場合に発生します。Lambda はこれらの障害に対して自動的に再試行して、耐久性のある関数が一時的なインフラストラクチャの問題から回復できるようにします。

### バックエンドの再試行シナリオ
<a name="durable-backend-retry-scenarios"></a>

Lambda は、次のシナリオが発生した場合に関数を自動的に再試行します。
+ **内部サービスエラー** – Lambda または耐久性のある実行サービスが 5xx エラー (一時的なサービスの問題を示す) を返す場合。
+ **スロットリング** – 同時実行制限またはサービスクォータが原因で関数がスロットリングされた場合。
+ **タイムアウト** – SDK がタイムアウト期間内に耐久性のある実行サービスに到達できない場合。
+ **サンドボックス初期化の失敗** – Lambda が実行環境を初期化できない場合。
+ **ランタイムエラー** – Lambda ランタイムで out-of-memory エラーやプロセスクラッシュなど、関数コード外のエラーが発生した場合。
+ **無効なチェックポイントトークンのエラー** – チェックポイントトークンが無効になった場合、通常はサービス側の状態の変化が原因です。

次の表で、SDK がこれらのシナリオを処理する方法について説明します。


| シナリオ | どうなるのか | 計測への影響 | 
| --- | --- | --- | 
| 耐久性のあるハンドラー外のランタイムエラー (OOM、タイムアウト、クラッシュ) | Lambda は呼び出しを自動的に再試行します。SDK は最後のチェックポイントからリプレイし、完了したステップをスキップします。 | エラーペイロードサイズ \$1 再試行ごとに 1 回のオペレーション | 
| CheckpointDurableExecution / GetDurableExecutionState APIs の呼び出し時のサービスエラー (5xx) または タイムアウト | Lambda は呼び出しを自動的に再試行します。SDK は最後のチェックポイントから再生されます。 | エラーペイロードサイズ \$1 再試行ごとに 1 回のオペレーション | 
| CheckpointDurableExecution / GetDurableExecutionState APIs の呼び出し時のスロットリング (429) または無効なチェックポイントトークン | Lambda はエクスポネンシャルバックオフを使用して呼び出しを自動的に再試行します。SDK は最後のチェックポイントから再生されます。 | エラーペイロードサイズ \$1 再試行ごとに 1 回のオペレーション | 
| CheckpointDurableExecution / GetDurableExecutionState APIs の場合のクライアントエラー (4xx、ただし 429 と無効なトークンを除く) | SDK は実行を FAILED としてマークします。エラーは永続的な問題を示しているため、自動再試行は行われません。 | エラーペイロードサイズ | 

バックエンドの再試行ではエクスポネンシャルバックオフを使用し、関数が成功するか、実行タイムアウトに達するまで続行します。リプレイ中、SDK は完了したチェックポイントをスキップし、最後に成功した操作の実行を続行し、関数が完了した作業を再実行しないようにします。

## 再試行のベストプラクティス
<a name="durable-retry-best-practices"></a>

再試行戦略を設定するときは、次のベストプラクティスに従ってください。
+ **明示的な再試行戦略を設定する** – 本番環境でデフォルトの再試行動作に依存しないでください。ユースケースに適した最大試行回数とバックオフ間隔を使用して、明示的な再試行戦略を設定します。
+ **条件付き再試行を使用する** – 一時的なエラー (レート制限、タイムアウト) のみを再試行し、永続的なエラー (検証エラー、未検出) ではフェイルファストする `shouldRetry` ロジックを実装します。
+ **適切な最大試行回数を設定する** – 回復性と実行時間のバランスを取ります。再試行回数が多すぎると障害検出が遅れる可能性がありますが、少なすぎると不要な障害が発生する可能性があります。
+ **エクスポネンシャルバックオフを使用する** – エクスポネンシャルバックオフは、ダウンストリームサービスの負荷を軽減し、一時的な障害から回復できる可能性を高めます。
+ **エラーが発生しやすいコードをステップでラップする** – ステップ外のコードを自動的に再試行することはできません。外部 API コール、データベースクエリ、その他のエラーが発生しやすい操作を再試行戦略でステップごとにラップします。
+ **再試行メトリクスをモニタリングする** – Amazon CloudWatch でステップ再試行操作と実行失敗を追跡して、パターンを特定し、再試行戦略を最適化します。

# べき等性
<a name="durable-execution-idempotency"></a>

耐久関数は、実行名から実行を開始するための組み込みのべき等性を提供します。実行名を指定すると、Lambda はそれを使用して重複する実行を防ぎ、呼び出しリクエストの安全な再試行を可能にします。ステップにはデフォルトで at-least-once の実行セマンティクスがあります。リプレイ中、SDK は完了したステップを再実行せずにチェックポイントされた結果を返しますが、完了前に発生する可能性がある再試行を処理できるように、ビジネスロジックはべき等性である必要があります。

**注記**  
Lambda イベントソースマッピング (ESM) は、起動時のべき等性をサポートしていません。したがって、各呼び出し (再試行を含む) は新しい耐久性のある実行を開始します。イベントソースマッピングを使用してべき等性の実行を確実に行うには、[の Powertools for AWS Lambda](https://docs.aws.amazon.com//powertools/) などの関数コードにべき等性ロジックを実装するか、通常の Lambda 関数をプロキシ (ディスパッチャー) として使用して、べき等性キー (実行名パラメータ) を使用して耐久性関数を呼び出します。

## 実行名
<a name="durable-idempotency-execution-names"></a>

耐久関数を呼び出すときに実行名を指定できます。実行名はべき等性キーとして機能し、重複した実行を作成せずに呼び出しリクエストを安全に再試行できます。名前を指定しない場合、Lambda は一意の実行 ID を自動的に生成します。

この名前は、ユーザーのアカウント内とリージョン内で一意でなければなりません。すでに存在する実行名で関数を呼び出す場合、Lambda の動作は既存の実行の状態とペイロードが一致するかどうかによって異なります。

## べき等性の動作
<a name="durable-idempotency-behavior"></a>

次の表は、実行名を指定したかどうか、既存の実行状態、ペイロードが一致するかどうかに基づいて、Lambda が呼び出しリクエストを処理する方法を示しています。


| シナリオ | 名前が指定されていますか? | 既存の実行状態 | ペイロードは同一ですか? | 行動 | 
| --- | --- | --- | --- | --- | 
| 1 | 不可 | 該当なし | 該当なし | 新しい実行が開始される: Lambda は一意の実行 ID を生成し、新しい実行を開始する | 
| 2 | はい | 存在したことがない、または保持の有効期限が切れている | 該当なし | 新しい実行が開始される: Lambda は指定された名前で新しい実行を開始する | 
| 3 | はい | 実行中 | はい | 冪等性の開始: Lambda は、重複を開始せずに既存の実行情報を返します。同期呼び出しの場合、これは実行中の実行への再アタッチとして動作します。 | 
| 4 | はい | 実行中 | 不可 | エラー: この名前の実行はすでに異なるペイロードで実行されているため、Lambda は DurableExecutionAlreadyExists エラーを返す | 
| 5 | はい | クローズ済み (成功、失敗、停止、またはタイムアウト) | はい | べき等性の開始: Lambda は、新しい実行を開始せずに既存の実行情報を返します。クローズされた実行結果が返されます | 
| 6 | はい | クローズ済み (成功、失敗、停止、またはタイムアウト) | 不可 | エラー: この名前の実行は別のペイロードですでに完了しているため、Lambda は DurableExecutionAlreadyExists エラーを返します | 

**注記**  
シナリオ 3 と 5 は、重複を作成するのではなく、既存の実行情報を返すことで、Lambda が重複した呼び出しリクエストを安全に処理する、べき等性の動作を示しています。

## ステップのべき等性
<a name="durable-idempotency-steps"></a>

ステップには、デフォルトで at-least-once 実行セマンティクスがあります。待機、コールバック、または失敗後に関数が再生されると、SDK はチェックポイントログに対して各ステップをチェックします。すでに完了したステップの場合、SDK はステップロジックを再実行せずにチェックポイントされた結果を返します。ただし、ステップが失敗した場合、またはステップが完了する前に関数が中断された場合、ステップは複数回実行される可能性があります。

ステップでラップされたビジネスロジックは、発生する可能性のある再試行を処理するように、べき等性である必要があります。べき等性キーを使用して、ステップが再試行された場合でも、支払いやデータベース書き込みなどのオペレーションが 1 回だけ実行されるようにします。

**例: ステップでのべき等性キーの使用**

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';
import { randomUUID } from 'crypto';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Generate idempotency key once
    const idempotencyKey = await context.step('generate-key', async () => {
      return randomUUID();
    });
    
    // Use idempotency key in payment API to prevent duplicate charges
    const payment = await context.step('process-payment', async () => {
      return paymentAPI.charge({
        amount: event.amount,
        idempotencyKey: idempotencyKey
      });
    });
    
    return { statusCode: 200, payment };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
import uuid

@durable_execution
def handler(event, context: DurableContext):
    # Generate idempotency key once
    idempotency_key = context.step(
        lambda _: str(uuid.uuid4()),
        name='generate-key'
    )
    
    # Use idempotency key in payment API to prevent duplicate charges
    payment = context.step(
        lambda _: payment_api.charge(
            amount=event['amount'],
            idempotency_key=idempotency_key
        ),
        name='process-payment'
    )
    
    return {'statusCode': 200, 'payment': payment}
```

------

実行モードを `AT_MOST_ONCE_PER_RETRY` に設定することで、at-most-once の実行セマンティクスを使用するようにステップを設定できます。これにより、ステップは再試行ごとに最大 1 回実行されますが、ステップが完了する前に関数が中断された場合はまったく実行されない可能性があります。

SDK は、リプレイ時にステップ名と実行順序がチェックポイントログと一致していることを検証することで、決定的なリプレイを実行します。コードが別の順序または名前でステップを実行しようとすると、SDK は `NonDeterministicExecutionError` をスローします。

**完了したステップでのリプレイの仕組み:**

1. 最初の呼び出し: 関数はステップ A を実行し、チェックポイントを作成してから待機する

1. 2 回目の呼び出し (待機後): 関数は最初から再生されますが、ステップ A はチェックポイントされた結果をすぐに返すため、再実行されず、そのままステップ B に進みます。

1. 3 回目の呼び出し (別の待機後): 関数は最初から再生されますが、ステップ A とステップ B はチェックポイントされた結果をすぐに返すため、そのままステップ C に進みます。

このリプレイメカニズムにより、完了したステップが再実行されることはありませんが、ビジネスロジックは完了前に再試行を処理するべき等性である必要があります。

# Lambda の耐久関数のテスト
<a name="durable-testing"></a>

AWS は、ローカルとクラウドの両方で実行を動作させ検査できる耐久関数専用のテスト SDK を提供します。言語用のテスト SDK をインストールします。

------
#### [ TypeScript ]

```
npm install --save-dev @aws/aws-durable-execution-sdk-js-testing
```

詳細なドキュメントと例については、GitHub の「[TypeScript testing SDK](https://github.com/aws/aws-durable-execution-sdk-js/tree/development/packages/aws-durable-execution-sdk-js-testing)」を参照してください。

------
#### [ Python ]

```
pip install aws-durable-execution-sdk-python-testing
```

詳細なドキュメントと例については、GitHub の「[Python testing SDK](https://github.com/aws/aws-durable-execution-sdk-python-testing)」を参照してください。

------

テスト SDK には、高速ユニットテスト用のローカルテストと、デプロイされた関数に対する統合テスト用のクラウドテストの 2 つのテストモードがあります。

## ローカルテスト
<a name="durable-local-testing"></a>

ローカルテストでは、デプロイされたリソースを必要とせずに、開発環境で耐久関数を実行します。テストランナーは関数コードを直接実行し、検査のためにすべてのオペレーションをキャプチャします。

ユニットテスト、テスト駆動型開発、CI/CD パイプラインにはローカルテストを使用します。テストは、ネットワークレイテンシーや追加コストなしでローカルで実行されます。

**テストの例:**

------
#### [ TypeScript ]

```
import { withDurableExecution } from '@aws/aws-durable-execution-sdk-js';
import { DurableFunctionTestRunner } from '@aws/aws-durable-execution-sdk-js-testing';

const handler = withDurableExecution(async (event, context) => {
  const result = await context.step('calculate', async () => {
    return event.a + event.b;
  });
  return result;
});

test('addition works correctly', async () => {
  const runner = new DurableFunctionTestRunner({ handler });
  const result = await runner.run({ a: 5, b: 3 });
  
  expect(result.status).toBe('SUCCEEDED');
  expect(result.result).toBe(8);
  
  const step = result.getStep('calculate');
  expect(step.result).toBe(8);
});
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
from aws_durable_execution_sdk_python_testing import DurableFunctionTestRunner
from aws_durable_execution_sdk_python.execution import InvocationStatus

@durable_execution
def handler(event: dict, context: DurableContext) -> int:
    result = context.step(lambda _: event["a"] + event["b"], name="calculate")
    return result

def test_addition():
    runner = DurableFunctionTestRunner(handler=handler)
    with runner:
        result = runner.run(input={"a": 5, "b": 3}, timeout=10)
    
    assert result.status is InvocationStatus.SUCCEEDED
    assert result.result == 8
    
    step = result.get_step("calculate")
    assert step.result == 8
```

------

テストランナーは、最終結果、個々のステップ結果、待機オペレーション、コールバック、エラーなどの実行状態をキャプチャします。オペレーションを名前で検査するか、すべての操作を繰り返して実行動作を検証できます。

### 実行ストア
<a name="durable-execution-stores"></a>

テスト SDK は、実行ストアを使用してテスト実行データを永続化します。デフォルトでは、テストは高速かつクリーンアップを必要としないインメモリストアを使用します。実行履歴をデバッグまたは分析するには、実行を JSON ファイルとして保存するファイルシステムストアを使用できます。

**インメモリストア (デフォルト):**

インメモリストアは、テスト実行中に実行データをメモリに保持します。テストが完了するとデータが失われるため、テスト終了後に実行を検査する必要のない標準ユニットテストや CI/CD パイプラインに最適です。

**ファイルシステムストア:**

ファイルシステムストアは、実行データを JSON ファイルとしてディスクに保持します。各実行は個別のファイルに保存されるため、テストの完了後に実行履歴を簡単に検査できます。複雑なテスト障害をデバッグしたり、実行パターンを経時的に分析したりする場合は、ファイルシステムストアを使用します。

環境変数を設定して、ストアを設定する:

```
# Use filesystem store
export AWS_DEX_STORE_TYPE=filesystem
export AWS_DEX_STORE_PATH=./test-executions

# Run tests
pytest tests/
```

実行ファイルはサニタイズされた名前で保存され、オペレーション、チェックポイント、結果を含む完全な実行状態が保持されます。ファイルシステムストアが存在しない場合、ストレージディレクトリが自動的に作成されます。

## クラウドテスト
<a name="durable-cloud-testing"></a>

クラウドテストは、AWS にデプロイされた耐久関数を呼び出し、Lambda API を使用して実行履歴を取得します。クラウドテストを使用して、実際の AWS サービスと設定を備えた本番環境のような環境における動作を検証します。

クラウドテストには、デプロイされた関数と、関数を呼び出して実行履歴を読み取るためのアクセス許可を持つ AWS 認証情報が必要です。

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction",
                "lambda:GetDurableExecution",
                "lambda:GetDurableExecutionHistory"
            ],
            "Resource": "arn:aws:lambda:region:account-id:function:function-name"
        }
    ]
}
```

**クラウドテストの例:**

------
#### [ TypeScript ]

```
import { DurableFunctionCloudTestRunner } from '@aws/aws-durable-execution-sdk-js-testing';

test('deployed function processes orders', async () => {
  const runner = new DurableFunctionCloudTestRunner({
    functionName: 'order-processor',
    region: 'us-east-1'
  });
  
  const result = await runner.run({ orderId: 'order-123' });
  
  expect(result.status).toBe('SUCCEEDED');
  expect(result.result.status).toBe('completed');
});
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python_testing import (
    DurableFunctionCloudTestRunner,
    DurableFunctionCloudTestRunnerConfig
)

def test_deployed_function():
    config = DurableFunctionCloudTestRunnerConfig(
        function_name="order-processor",
        region="us-east-1"
    )
    runner = DurableFunctionCloudTestRunner(config=config)
    
    result = runner.run(input={"orderId": "order-123"})
    
    assert result.status is InvocationStatus.SUCCEEDED
    assert result.result["status"] == "completed"
```

------

クラウドテストは、実際にデプロイされた関数を呼び出し、AWS から実行履歴を取得します。これにより、他の AWS サービスとの統合を検証し、パフォーマンス特性を検証し、本番稼働用のデータや設定でテストできます。

## テスト対象
<a name="durable-testing-patterns"></a>

実行結果、オペレーション動作、エラー処理を検証して、耐久関数をテストします。実装の詳細ではなく、ビジネスロジックの正確性に焦点を当てます。

**実行結果の検証:** 関数が指定された入力の期待値を返すことを確認します。成功した実行とエラーケースの両方をテストして、関数が無効な入力を適切に処理することを確認します。

**操作の実行を検査する:** ステップ、待機、コールバックが期待どおりに実行されることを確認します。ステップの結果をチェックして、中間オペレーションが正しい値を生成することを確認します。待機オペレーションが適切なタイムアウトで設定されていること、およびコールバックが正しい設定で作成されていることを確認します。

**テストエラー処理:** 無効な入力が渡された場合、関数が適切に失敗し、説明的なエラーメッセージが表示されることを確認します。一時的な障害をシミュレートし、オペレーションが適切に再試行されることを確認して、再試行動作をテストします。永続的な障害によって不要な再試行がトリガーされないことを確認します。

**ワークフローの検証:** 多段式ワークフローの場合、オペレーションが正しい順序で実行されることを確認します。条件分岐をテストして、異なる実行パスが正しく動作することを確認します。並列オペレーションが同時に実行され、期待される結果が得られることを検証します。

SDK ドキュメントリポジトリには、多段式ワークフロー、エラーシナリオ、タイムアウト処理、ポーリングパターンなど、テストパターンの広範な例が含まれています。

## テスト戦略
<a name="durable-testing-strategy"></a>

開発中および CI/CD パイプラインでユニットテストにローカルテストを使用します。ローカルテストは高速に実行でき、AWS 認証情報を必要とせず、コードの変更に関するフィードバックをすぐに提供します。ローカルテストを作成して、ビジネスロジック、エラー処理、オペレーション動作を検証します。

本番環境にデプロイする前に、統合テストにクラウドテストを使用します。クラウドテストは、実際の AWS サービスと設定を使用して動作を検証し、パフォーマンス特性を検証し、エンドツーエンドのワークフローをテストします。ステージング環境でクラウドテストを実行して、本番環境に到達する前に統合の問題を検出します。

ローカルテストで外部依存関係をモック化して、関数ロジックを分離し、テストを高速化します。クラウドテストを使用して、データベース、API、その他の AWS サービスなどの外部サービスとの実際の統合を検証します。

1 つの特定の動作を検証する重点テストを記述します。テスト対象を説明するわかりやすいテスト名を使用します。関連するテストをグループ化し、一般的なセットアップコードに試験装置を使用します。テストはシンプルに保ち、わかりにくい複雑なテストロジックは避けてください。

## デバッグの失敗
<a name="durable-testing-debugging"></a>

テストが失敗したら、実行結果を検査して、何が失敗したかを把握します。実行ステータスをチェックして、関数が成功、失敗、またはタイムアウトしたかどうかを確認します。エラーメッセージを読み、障害の原因を把握します。

個々のオペレーション結果を調べて、動作が予想と異なる場所を見つけます。ステップの結果をチェックして、生成された値を確認します。オペレーションの順序を確認し、オペレーションが予想される順序で実行されていることを確認します。オペレーションをカウントして、適切な数のステップ、待機、コールバックが作成されていることを確認します。

一般的な問題には、リプレイ時に異なる結果を生成する非決定的なコード、リプレイ中に破損するグローバル変数を介した共有状態、条件付きロジックエラーによる操作の欠落などがあります。標準的なデバッガーとログを使用して、関数コードをステップスルーし、実行フローを追跡します。

クラウドテストの場合は、CloudWatch Logs の実行履歴を調べて、詳細なオペレーションログを確認します。トレースを使用して、サービス全体の実行フローを追跡し、ボトルネックを特定します。

# 耐久関数のモニタリング
<a name="durable-monitoring"></a>

CloudWatch メトリクス、CloudWatch Logs、トレースを使用して、耐久関数をモニタリングできます。耐久関数は長期間実行でき、複数の関数呼び出しにまたがることができるため、それらをモニタリングするには、チェックポイント、状態遷移、リプレイ動作など、一意の実行パターンを理解する必要があります。

## CloudWatch メトリクス
<a name="durable-monitoring-metrics"></a>

Lambda は、追加料金なしで CloudWatch にメトリクスを自動的に発行します。耐久関数は、標準の Lambda メトリクスを超える追加のメトリクスを提供し、長時間におよぶワークフロー、状態管理、リソース使用率をモニタリングするのに役立ちます。

### 耐久性のある実行メトリクス
<a name="durable-monitoring-execution-metrics"></a>

Lambda は、耐久性のある実行に対して次のメトリクスを出力します。


| メトリクス | 説明 | 
| --- | --- | 
| ApproximateRunningDurableExecutions | RUNNING 状態における耐久性のある実行の数 | 
| ApproximateRunningDurableExecutionsUtilization | アカウントで実行中の最大耐久実行クォータに対する現在の使用率 | 
| DurableExecutionDuration | 耐久性のある実行が RUNNING 状態のままであるミリ秒単位の経過実測時間 | 
| DurableExecutionStarted | 開始された耐久性のある実行の数 | 
| DurableExecutionStopped | StopDurableExecution API を使用して停止した耐久性のある実行の数 | 
| DurableExecutionSucceeded | 正常に完了した耐久性のある実行の数 | 
| DurableExecutionFailed | 失敗で完了した耐久性のある実行の数 | 
| DurableExecutionTimedOut | 設定された実行タイムアウトを超えた耐久性のある実行の数 | 
| DurableExecutionOperations | 耐久性のある実行内で実行されたオペレーションの累積数 (最大: 3,000) | 
| DurableExecutionStorageWrittenBytes | 耐久性のある実行によって保持されるバイト単位のデータの累積量 (最大: 100 MB) | 

### CloudWatch メトリクス
<a name="durable-monitoring-standard-metrics"></a>

Lambda は、耐久関数の標準の呼び出し、パフォーマンス、および同時実行メトリクスを出力します。耐久性のある実行は、チェックポイントやリプレイの進行に伴って複数の関数呼び出しにまたがる可能性があるため、これらのメトリクスの動作は標準関数とは異なります。
+ **呼び出し:** リプレイを含む各関数呼び出しをカウントします。1 回の耐久性のある実行で、複数の呼び出しデータポイントを生成できます。
+ **期間:** 各関数の呼び出しを別々に測定します。1 回の耐久性のある実行にかかる合計時間に `DurableExecutionDuration` を使用します。
+ **エラー:** 関数の呼び出しエラーを追跡します。実行レベルの障害には `DurableExecutionFailed` を使用します。

標準 Lambda メトリクスの完全なリストについては、「[Lambda 関数のメトリクスのタイプ](https://docs.aws.amazon.com//lambda/latest/dg/monitoring-metrics-types.html)」を参照してください。

### CloudWatch アラームの作成
<a name="durable-monitoring-alarms"></a>

メトリクスがしきい値を超えたときに通知する CloudWatch アラームを作成します。一般的なアラームは次のとおりです。
+ `ApproximateRunningDurableExecutionsUtilization` がクォータの 80% を超えている
+ `DurableExecutionFailed` しきい値を超えて増加している
+ `DurableExecutionTimedOut` は実行がタイムアウトしていることを示す
+ `DurableExecutionStorageWrittenBytes` がストレージ制限に近づく

詳細については、「[Amazon CloudWatch アラームを使用する](https://docs.aws.amazon.com//AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html)」を参照してください。

## EventBridge イベント
<a name="durable-monitoring-eventbridge"></a>

Lambda は、耐久性のある実行のステータス変更イベントを EventBridge に発行します。これらのイベントを使用して、ワークフローをトリガーしたり、通知を送信したり、耐久関数全体で実行ライフサイクルの変更を追跡したりできます。

### 耐久性のある実行のステータス変更イベント
<a name="durable-eventbridge-status-changes"></a>

Lambda は、耐久性のある実行がステータスを変更するたびに EventBridge にイベントを出力します。これらのイベントの特性は次のとおりです。
+ **ソース:** `aws.lambda`
+ **詳細タイプ:** `Durable Execution Status Change`

ステータス変更イベントは、次の実行状態で発行されます。
+ `RUNNING` – 実行が開始されました
+ `SUCCEEDED` – 実行が正常に完了しました
+ `STOPPED` – StopDurableExecution API を使用して実行を停止しました
+ `FAILED` – エラーにより実行に失敗しました
+ `TIMED_OUT` – 実行が設定されたタイムアウトを超えました

次の例は、耐久性のある実行のステータス変更イベントを示しています。

```
{
  "version": "0",
  "id": "d019b03c-a8a3-9d58-85de-241e96206538",
  "detail-type": "Durable Execution Status Change",
  "source": "aws.lambda",
  "account": "123456789012",
  "time": "2025-11-20T13:08:22Z",
  "region": "us-east-1",
  "resources": [],
  "detail": {
    "durableExecutionArn": "arn:aws:lambda:us-east-1:123456789012:function:my-function:$LATEST/durable-execution/090c4189-b18b-4296-9d0c-cfd01dc3a122/9f7d84c9-ea3d-3ffc-b3e5-5ec51c34ffc9",
    "durableExecutionName": "order-123",
    "functionArn": "arn:aws:lambda:us-east-1:123456789012:function:my-function:2",
    "status": "RUNNING",
    "startTimestamp": "2025-11-20T13:08:22.345Z"
  }
}
```

終了状態 (`SUCCEEDED`、`STOPPED`、`FAILED`、`TIMED_OUT`) の場合、イベントには実行が完了したことを示す `endTimestamp` フィールドが含まれます。

### EventBridge ルールの作成
<a name="durable-eventbridge-rules"></a>

Amazon Simple Notification Service、Amazon Simple Queue Service、またはその他の Lambda 関数などのターゲットに耐久性のある実行のステータス変更イベントをルーティングするためのルールを作成します。

次の例では、耐久性のある実行のすべてのステータスの変更に一致するルールを作成します。

```
{
  "source": ["aws.lambda"],
  "detail-type": ["Durable Execution Status Change"]
}
```

次の例では、失敗した実行のみに一致するルールを作成します。

```
{
  "source": ["aws.lambda"],
  "detail-type": ["Durable Execution Status Change"],
  "detail": {
    "status": ["FAILED"]
  }
}
```

次の例では、特定の関数のステータス変更に一致するルールを作成します。

```
{
  "source": ["aws.lambda"],
  "detail-type": ["Durable Execution Status Change"],
  "detail": {
    "functionArn": [{
      "prefix": "arn:aws:lambda:us-east-1:123456789012:function:my-function"
    }]
  }
}
```

ルールの作成の詳細については、「EventBridge ユーザーガイド」の「[Amazon EventBridge チュートリアル](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-tutorial.html)」を参照してください。

## AWS X-Ray トレース
<a name="durable-monitoring-xray"></a>

耐久関数で X-Ray トレースを有効にできます。Lambda は X-Ray トレースヘッダーを耐久性のある実行に渡します。これにより、ワークフロー全体でリクエストをトレースできます。

Lambda コンソールを使用して X-Ray; トレースを有効にするには、関数を選択し、設定、モニタリング、オペレーションツールを選択し、X-Ray でアクティブトレースを有効にします。

AWS CLI を使用して X-Ray トレースを有効にするには:

```
aws lambda update-function-configuration \
    --function-name my-durable-function \
    --tracing-config Mode=Active
```

AWS SAM を使用して AWS X-Ray トレースを有効にするには:

```
Resources:
  MyDurableFunction:
    Type: AWS::Serverless::Function
    Properties:
      Tracing: Active
      DurableConfig:
        ExecutionTimeout: 3600
```

X-Ray の詳細については、「[AWS X-Ray デベロッパーガイド](https://docs.aws.amazon.com//xray/latest/devguide/aws-xray.html)」を参照してください。

# Lambda の耐久性のある関数におけるベストプラクティス
<a name="durable-best-practices"></a>

耐久性のある関数には、従来の Lambda 関数とは異なるパターンを必要とする再生ベースの実行モデルが使用されます。信頼性が高く、費用対効果の高いワークフローを構築するには、以下のベストプラクティスに従ってください。

## 決定的コードを記述する
<a name="durable-determinism"></a>

再生中、関数は最初から実行され、元の実行と同じ実行パスに従う必要があります。耐久性のあるオペレーション以外のコードは決定的で、同じ入力で同じ結果が生成される必要があります。

**非決定的なオペレーションをステップでラップします**
+ ランダム数値生成と UUID
+ 現在の時刻またはタイムスタンプ
+ 外部 API コールとデータベースクエリ
+ ファイルシステムの操作

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';
import { randomUUID } from 'crypto';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Generate transaction ID inside a step
    const transactionId = await context.step('generate-transaction-id', async () => {
      return randomUUID();
    });
    
    // Use the same ID throughout execution, even during replay
    const payment = await context.step('process-payment', async () => {
      return processPayment(event.amount, transactionId);
    });
    
    return { statusCode: 200, transactionId, payment };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
import uuid

@durable_execution
def handler(event, context: DurableContext):
    # Generate transaction ID inside a step
    transaction_id = context.step(
        lambda _: str(uuid.uuid4()),
        name='generate-transaction-id'
    )
    
    # Use the same ID throughout execution, even during replay
    payment = context.step(
        lambda _: process_payment(event['amount'], transaction_id),
        name='process-payment'
    )
    
    return {'statusCode': 200, 'transactionId': transaction_id, 'payment': payment}
```

------

**重要**  
グローバル変数やクロージャを使用して、ステップ間の状態を共有しないでください。戻り値を通じてデータを渡します。ステップはキャッシュされた結果を返しますが、グローバル変数がリセットされるため、再生中にグローバル状態が中断されます。

**クロージャミューテーションを避ける:** クロージャでキャプチャされた変数は、再生中にミューテーションを失う可能性があります。ステップはキャッシュされた結果を返しますが、ステップ以外の変数更新は再生されません。

------
#### [ TypeScript ]

```
// ❌ WRONG: Mutations lost on replay
export const handler = withDurableExecution(async (event, context) => {
  let total = 0;
  
  for (const item of items) {
    await context.step(async () => {
      total += item.price; // ⚠️ Mutation lost on replay!
      return saveItem(item);
    });
  }
  
  return { total }; // Inconsistent value!
});

// ✅ CORRECT: Accumulate with return values
export const handler = withDurableExecution(async (event, context) => {
  let total = 0;
  
  for (const item of items) {
    total = await context.step(async () => {
      const newTotal = total + item.price;
      await saveItem(item);
      return newTotal; // Return updated value
    });
  }
  
  return { total }; // Consistent!
});

// ✅ EVEN BETTER: Use map for parallel processing
export const handler = withDurableExecution(async (event, context) => {
  const results = await context.map(
    items,
    async (ctx, item) => {
      await ctx.step(async () => saveItem(item));
      return item.price;
    }
  );
  
  const total = results.getResults().reduce((sum, price) => sum + price, 0);
  return { total };
});
```

------
#### [ Python ]

```
# ❌ WRONG: Mutations lost on replay
@durable_execution
def handler(event, context: DurableContext):
    total = 0
    
    for item in items:
        context.step(
            lambda _: save_item_and_mutate(item, total),  # ⚠️ Mutation lost on replay!
            name=f'save-item-{item["id"]}'
        )
    
    return {'total': total}  # Inconsistent value!

# ✅ CORRECT: Accumulate with return values
@durable_execution
def handler(event, context: DurableContext):
    total = 0
    
    for item in items:
        total = context.step(
            lambda _: save_item_and_return_total(item, total),
            name=f'save-item-{item["id"]}'
        )
    
    return {'total': total}  # Consistent!

# ✅ EVEN BETTER: Use map for parallel processing
@durable_execution
def handler(event, context: DurableContext):
    def process_item(ctx, item):
        ctx.step(lambda _: save_item(item))
        return item['price']
    
    results = context.map(items, process_item)
    total = sum(results.get_results())
    
    return {'total': total}
```

------

## べき等性用の設計
<a name="durable-idempotency"></a>

再試行や再生により、オペレーションが複数回実行される場合があります。非べき等性オペレーションでは副作用が重複します (お客様に 2 回請求したり、複数の E メールを送信したりするなど)。

**べき等性トークンの使用:** ステップ内でトークンを生成し、オペレーションの重複を防止するため、外部 API コールを使用して含めます。

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Generate idempotency token once
    const idempotencyToken = await context.step('generate-idempotency-token', async () => {
      return crypto.randomUUID();
    });
    
    // Use token to prevent duplicate charges
    const charge = await context.step('charge-payment', async () => {
      return paymentService.charge({
        amount: event.amount,
        cardToken: event.cardToken,
        idempotencyKey: idempotencyToken
      });
    });
    
    return { statusCode: 200, charge };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext
import uuid

@durable_execution
def handler(event, context: DurableContext):
    # Generate idempotency token once
    idempotency_token = context.step(
        lambda _: str(uuid.uuid4()),
        name='generate-idempotency-token'
    )
    
    # Use token to prevent duplicate charges
    def charge_payment(_):
        return payment_service.charge(
            amount=event['amount'],
            card_token=event['cardToken'],
            idempotency_key=idempotency_token
        )
    
    charge = context.step(charge_payment, name='charge-payment')
    
    return {'statusCode': 200, 'charge': charge}
```

------

**「at-most-once」セマンティックの使用:** 重複してはならない重要なオペレーション (金融トランザクション、インベントリ控除) には、「at-most-once」の実行モードを設定します。

------
#### [ TypeScript ]

```
// Critical operation that must not duplicate
await context.step('deduct-inventory', async () => {
  return inventoryService.deduct(event.productId, event.quantity);
}, {
  executionMode: 'AT_MOST_ONCE_PER_RETRY'
});
```

------
#### [ Python ]

```
# Critical operation that must not duplicate
context.step(
    lambda _: inventory_service.deduct(event['productId'], event['quantity']),
    name='deduct-inventory',
    config=StepConfig(execution_mode='AT_MOST_ONCE_PER_RETRY')
)
```

------

**データベースのべき等性:** レコードの重複を防止するめ、「check-before-write」パターン、条件付き更新、アップサートオペレーションを使用してください。

## 状態を効率的に管理する
<a name="durable-state-management"></a>

すべてのチェックポイントにより、状態を永続的ストレージに保存されます。大規模な状態オブジェクトはコストが増加し、チェックポイント処理が遅くなり、パフォーマンスに影響します。重要なワークフローの調整データのみを保存します。

**状態を最小限に維持します**
+ 完全なオブジェクトではなく、ID およびリファレンスを保存する
+ 必要に応じてステップ内で詳細データを取得する
+ 大規模なデータに Amazon S3 または DynamoDB を使用し、状態でリファレンスを渡す
+ ステップ間で大規模なペイロードを渡すことを避ける

------
#### [ TypeScript ]

```
import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js';

export const handler = withDurableExecution(
  async (event: any, context: DurableContext) => {
    // Store only the order ID, not the full order object
    const orderId = event.orderId;
    
    // Fetch data within each step as needed
    await context.step('validate-order', async () => {
      const order = await orderService.getOrder(orderId);
      return validateOrder(order);
    });
    
    await context.step('process-payment', async () => {
      const order = await orderService.getOrder(orderId);
      return processPayment(order);
    });
    
    return { statusCode: 200, orderId };
  }
);
```

------
#### [ Python ]

```
from aws_durable_execution_sdk_python import durable_execution, DurableContext

@durable_execution
def handler(event, context: DurableContext):
    # Store only the order ID, not the full order object
    order_id = event['orderId']
    
    # Fetch data within each step as needed
    context.step(
        lambda _: validate_order(order_service.get_order(order_id)),
        name='validate-order'
    )
    
    context.step(
        lambda _: process_payment(order_service.get_order(order_id)),
        name='process-payment'
    )
    
    return {'statusCode': 200, 'orderId': order_id}
```

------

## 効果的なステップを設計する
<a name="durable-step-design"></a>

ステップは、耐久性のある関数の基礎的な作業単位です。適切に設計されたステップによってワークフローの理解、デバッグ、維持が容易になります。

**ステップ設計の原則**
+ **記述的な名前の使用** – 「`step1`」よりも「`validate-order`」のような名前により、ログやエラーが理解しやすくなります。
+ **名前を静的に維持** – タイムスタンプやランダムな値を含む動的な名前を使用しないでください。再生には、ステップ名が決定的である必要があります
+ **詳細度のバランス** – 複雑なオペレーションを重点的なステップに分割しますが、チェックポイントのオーバーヘッドが増加する小さなステップは避けてください。
+ **グループ関連オペレーション** – 同時に成功または失敗するオペレーションは同じステップに属します

## 待機オペレーションを効率的に使用
<a name="durable-wait-operations"></a>

待機オペレーションはリソースを消費したり、コストを発生させたりすることなく、実行を一時停止します。Lambda の実行を維持せずに、使用してください。

**時間ベースの待機:** `setTimeout` または `sleep` ではなく、`context.wait()` を遅延に使用します。

**外部コールバック:** 外部システムを待つときに `context.waitForCallback()` を使用します。無期限の待機を防止するため、必ずタイムアウトを設定してください。

**ポーリング:** エクスポネンシャルバックオフを持つ `context.waitForCondition()` を使用して、外部サービスを圧迫せずにポーリングします。

------
#### [ TypeScript ]

```
// Wait 24 hours without cost
await context.wait({ seconds: 86400 });

// Wait for external callback with timeout
const result = await context.waitForCallback(
  'external-job',
  async (callbackId) => {
    await externalService.submitJob({
      data: event.data,
      webhookUrl: `https://api.example.com/callbacks/${callbackId}`
    });
  },
  { timeout: { seconds: 3600 } }
);
```

------
#### [ Python ]

```
# Wait 24 hours without cost
context.wait(86400)

# Wait for external callback with timeout
result = context.wait_for_callback(
    lambda callback_id: external_service.submit_job(
        data=event['data'],
        webhook_url=f'https://api.example.com/callbacks/{callback_id}'
    ),
    name='external-job',
    config=WaitForCallbackConfig(timeout_seconds=3600)
)
```

------

## その他の考慮事項
<a name="durable-additional-considerations"></a>

**エラー処理:** ネットワークタイムアウトやレート制限など、一過性の障害を再試行します。無効な入力エラーや認証エラーなど、永続的な障害を再試行しないでください。適切な最大試行回数およびバックオフ率で再試行戦略を設定します。詳細な例については、「[エラー処理と再試行](durable-execution-sdk-retries.md)」を参照してください。

**パフォーマンス:** 完全なペイロードではなく、リファレンスを保存してチェックポイントのサイズを最小限に抑えます。`context.parallel()` および `context.map()` を使用して独立したオペレーションを同時に実行します。チェックポイントのオーバーヘッドを減らすためのバッチ関連オペレーション。

**バージョニング:** バージョン番号またはエイリアスを使用して関数を呼び出し、実行を特定のコードバージョンに固定します。新しいコードバージョンが古いバージョンの状態を処理できることを確認してください。再生を中断する原因となるステップの名前変更や動作の変更をしないでください。

**シリアル化:** オペレーションの入力および結果に JSON 互換タイプを使用します。耐久性のあるオペレーションに渡す前に、日付を ISO 文字列に変換し、カスタムオブジェクトをプレーンオブジェクトに変換します。

**モニタリング:** 実行 ID およびステップ名で構造化ログ記録を有効にします。エラー率および実行期間に CloudWatch アラームを設定します。トレースを使用してボトルネックを特定します。詳細なガイダンスについては、「[モニタリングとデバッグ](durable-monitoring.md)」を参照してください。

**テスト:** ハッピーパス、エラー処理、再生動作をテストします。コールバックおよび待機のタイムアウトシナリオをテストします。ローカルテストを使用して反復時間を短縮します。詳細なガイダンスについては、「[耐久性のある関数のテスト](durable-testing.md)」を参照してください。

**回避すべき一般的なミス:** `context.step()` の呼び出しをネストせず、代わりに子コンテキストを使用してください。非決定的なオペレーションはステップでラップします。コールバックのタイムアウトは必ず設定してください。ステップの詳細度はチェックポイントのオーバーヘッドでバランスを取ります。大規模なオブジェクトではなく、リファレンスを状態に保存します。

## その他のリソース
<a name="durable-additional-resources"></a>
+ [Python SDK のドキュメント](https://github.com/aws/aws-durable-execution-sdk-python/tree/main/docs) – 完全な API リファレンス、テストパターン、高度な例
+ [TypeScript SDK のドキュメント](https://github.com/aws/aws-durable-execution-sdk-js/tree/main/docs) – 完全な API リファレンス、テストパターン、高度な例