0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Step Functions Standardを業務工程のリトライの中心にし、SQSに受付・配送を担当させる構成

0
Posted at

title: "SQS・Lambda・Step Functions・AgentCore Runtimeのリトライ設計――タイムアウトと二重実行を防ぐ"
tags:

  • name: AWS
  • name: StepFunctions
  • name: lambda
  • name: SQS
  • name: AmazonBedrock
    private: true
    updated_at: ''
    id: null
    organization_url_name: null
    slide: false
    ignorePublish: false

はじめに

CloudFront・WAF・API Gatewayの後ろにLambda workerを置き、Amazon Bedrock AgentCore Runtimeへ処理を渡すバックエンドを考えます。処理が長くなると、HTTPリクエストの中で結果を待つ構成より、ジョブを受け付けて非同期に実行する構成が扱いやすくなります。

そこでSQSやStep Functionsを導入しますが、各サービスでリトライを増やすだけでは安全になりません。応答が失われた際、AgentCoreでは処理が続いているかもしれないからです。

この記事では、Step Functions Standardを業務工程のリトライの中心にし、SQSに受付・配送を担当させる構成を紹介します。2026年10月7日時点のAWS公式資料を基にした設計案です。設定値は初期案であり、実環境へのデプロイ・負荷試験を行った結果ではありません。

1. SQSとStep Functionsの役割を分ける

SQSは仕事をためるキュー、Step Functionsは仕事の手順を管理するオーケストレーターです。両方必要とは限りません。バースト吸収や受付と起動の分離が必要ならSQSを使い、不要なら受付Lambdaから直接StartExecutionする構成も選べます。

この図ではWAFをCloudFrontへ関連付けます。認証、ジョブ所有者の確認、アクセス権の判定はAPI・アプリケーション側で行います。

起動Lambdaはワークフロー開始を確認したらSQSメッセージの処理を成功として返します。AgentCoreの完了までSQSメッセージを保持しません。 開始後の失敗はStep Functionsに任せます。

受付では、キューへの投入成功を確認してから202を返します。状態DBとキューに別々に書き込む場合は、その間の障害も設計対象です。例えばDBに受付情報と送信待ち情報を一緒に記録し、後からキューへ確実に配送するOutbox方式、または未配送ジョブを回収する仕組みを用意します。202を返したジョブが起動されないまま残る状態を防ぐためです。

2. Standardを第一候補にする

長時間のAgentCore処理を待ち、工程ごとの失敗を追跡する用途ではStandard Workflowが第一候補です。

比較項目 Standard Express
最大実行時間 1年 5分
Callback 対応する統合で利用可能 非対応
実行モデル exactly-once。ただし明示的なRetryは再実行する 非同期はat-least-once、同期はat-most-once
主な適性 長時間・状態を保持する工程 短時間・高頻度・冪等な処理

Standardの実行保証は、外部APIの副作用まで一括して重複排除する保証ではありません。明示的なRetry、クライアントの再送、結果不明への対応を考えると、業務単位の冪等性は必要です。AWS:ワークフロータイプの選択

3. リトライの担当を決める

層 再試行する対象 方針
クライアント ジョブ受付の通信 同じIdempotency Keyを使う
受付SQS ワークフロー開始までの配送 StartExecution成功後は責任を移す
AWS SDK 短い通信・サービス障害 試行数を明示し少数回にする
Step Functions 個々の業務工程 エラーを分類してRetry・Catchする
AgentCore内のツール 個々の外部操作 副作用がある操作は操作単位で冪等化
運用者 原因修正後の再実行 既存の結果・副作用を確認する

例えば同じ処理をSQSで5回、Step Functionsで初回を含めて4回、SDKで合計3回試行すると、条件によっては5×4×3=60回の呼び出しに増えます。これは設計上の計算例で、AWSが常に60回実行するという意味ではありません。

SDKの既定値は言語・バージョン・設定に依存するため、利用するSDKで総試行数を確認して明示します。AWS:SDKのRetry設定

4. エラーを「一時障害」「恒久障害」「結果不明」に分ける

状況 推奨対応
Throttling・429 バックオフ。継続するなら投入量を減らす
一時的な500・RetryableConflict 冪等性を前提に少数回再試行
入力不正・Validation 再試行せず入力修正へ
AccessDenied・リソース設定不備 運用通知・設定修正へ
クォータ超過 流量調整やクォータ確認へ
タイムアウト・接続断 ジョブ状態を確認してから判断
業務条件を満たさない Choiceなどで業務結果として扱う
LLM出力の品質不足 品質改善の反復回数・費用を別途制限

InvokeAgentRuntimeにはThrottlingException、InternalServerException、RetryableConflictExceptionなどが定義されています。RuntimeClientErrorは複数の原因を持ちうるため、内容を見ずに一律で再試行対象にしません。AWS:InvokeAgentRuntime API

APIが正常応答を返しても、アプリケーションの応答本文が失敗を示す場合があります。Lambdaがエラー文字列を通常の戻り値として返すだけでは、Step FunctionsのRetryは発火しません。アダプターで例外を送出するか、応答をChoiceで判定する契約を決めます。

5. Retryには指数バックオフ・上限・ジッターを設定する

初期案はIntervalSeconds=2、BackoffRate=2、MaxAttempts=3、MaxDelaySeconds=30、JitterStrategy=FULLです。

MaxAttemptsは再試行回数です。3を指定すると、初回を含め最大4回になります。FULLでは待機時間がランダム化され、この例の待機範囲は0〜2秒、0〜4秒、0〜8秒です。MaxDelaySecondsは待機を長くしすぎないための上限です。AWS:Retry・Catch

以下はLambdaアダプターを呼び出すTaskの抜粋です。状態名・ARNの置換と後続状態の実装が必要で、そのままデプロイする定義ではありません。App.*は独自のエラー名です。

{
  "Type": "Task",
  "Resource": "arn:aws:states:::lambda:invoke",
  "Parameters": {
    "FunctionName": "<adapter-lambda-arn>",
    "Payload.$": "$"
  },
  "ResultPath": "$.dispatch",
  "Retry": [
    {
      "ErrorEquals": [
        "Lambda.ServiceException",
        "Lambda.AWSLambdaException",
        "Lambda.SdkClientException",
        "Lambda.TooManyRequestsException"
      ],
      "IntervalSeconds": 2,
      "BackoffRate": 2,
      "MaxAttempts": 3,
      "MaxDelaySeconds": 30,
      "JitterStrategy": "FULL"
    },
    {
      "ErrorEquals": ["App.TransientSafeToRetry"],
      "IntervalSeconds": 5,
      "BackoffRate": 2,
      "MaxAttempts": 2,
      "MaxDelaySeconds": 30,
      "JitterStrategy": "FULL"
    }
  ],
  "Catch": [
    {
      "ErrorEquals": [
        "App.OutcomeUnknown",
        "States.Timeout",
        "Sandbox.Timedout"
      ],
      "ResultPath": "$.error",
      "Next": "ReconcileJob"
    },
    {
      "ErrorEquals": ["States.ALL"],
      "ResultPath": "$.error",
      "Next": "RecordFailure"
    }
  ],
  "Next": "WaitForCompletion"
}

アダプターはAgentCoreの開始確認までを短時間で行います。SDKの通信タイムアウトをLambdaの制限より短くし、エラー分類を返す余裕を残します。Task全体にも上限を設けますが、タイムアウトで外部処理が自動停止すると仮定してはいけません。

ReconcileJobはジョブ状態を確認する工程です。States.ALLをRetryに使うと入力不正なども繰り返すため、再試行対象を列挙します。またStates.ALLで捕捉できないエラーや実行全体のタイムアウトに備え、ワークフロー外の失敗監視も用意します。

6. タイムアウトを「失敗」と決めつけない

未開始を確認できない場合はUNKNOWNとして保持し、一定時間の照合や運用判断へ進めます。DBに状態がないという事実だけで、直ちに未実行と判断できるとは限りません。

冪等性には次の情報を使います。

  • jobId:同じ業務依頼を識別する。
  • 入力ハッシュ:同じキーで異なる入力を受け付けない。
  • 状態:ACCEPTED、RUNNING、SUCCEEDED、FAILED、UNKNOWNなど。
  • 世代番号:旧workerが遅れて更新することを防ぐ。
  • 操作ID:外部更新・送信などの副作用を識別する。

AgentCore側でも、処理開始時に条件付き書き込みで実行権を取得します。完了済みなら既存結果を返し、実行中なら再起動しません。単に起動Lambdaでフラグを立てるだけでは、開始直後の障害や古いworkerの継続動作を十分に扱えません。

runtimeSessionIdは会話・セッションの識別子です。API仕様にジョブ重複排除の保証はないため、jobIdの代わりに使いません。

外部操作と状態DBを一つのトランザクションにできない場合、「外部更新は成功したが完了記録が失敗した」という窓が残ります。外部サービスの冪等性キー、既存結果の照会、補償処理などで対処します。

7. AgentCoreの非同期処理をどう待つか

AgentCore SDKは応答後のバックグラウンド処理に対応しています。ただしSDKのタスク追跡・セッションの健全性管理だけで、アプリケーションの永続的なジョブ管理が完成するわけではありません。結果やジョブ状態は外部ストレージへ保存します。AWS:AgentCoreの非同期処理

方式 向いている条件 注意点
Callback 完了時に通知できる Task Tokenと通知再送を管理
Wait→状態照会→Choice 状態DBを中心に作りたい 照会間隔・業務締切を設定
同期呼び出し 短時間で結果が返る 応答サイズ・時間・形式を検証

Callbackでは、例えばlambda:invoke.waitForTaskTokenで起動アダプターにトークンを渡し、完了通知用LambdaからSendTaskSuccessまたはSendTaskFailureを呼びます。これはアプリケーション側で構築する連携です。AWS:Callbackパターン

Task TokenはログやLLMへのプロンプトへ混入させず、必要なコンポーネントだけに渡します。結果保存後に完了通知し、通知の失敗に備えて再送情報を永続化します。タイムアウト後に届いた古い通知は、現在のジョブ世代と照合して扱います。

現在はInvokeAgentRuntimeをStep FunctionsのAWS SDK統合から直接呼び出せます。ただし、非同期ジョブの完了待機が自動で付くわけではありません。Lambdaアダプターが不要なケースもありますが、応答の変換や独自エラー分類が必要ならアダプターを残す価値があります。AWS:対応SDK統合

8. SQS・再実行・監視の実務ポイント

SQSの可視性タイムアウトは、起動Lambdaのタイムアウトの6倍以上にバッチウィンドウを加える設定がAWSの推奨です。maxReceiveCountは5以上を初期基準にし、Partial Batch Responseで失敗メッセージだけを再配送します。AWS:SQSイベントソースの設定

StandardのStartExecutionは、実行中の同じ名前・同じ入力に対して冪等です。実行名をjobIdから決め、入力を固定します。完了済みや入力不一致ではExecutionAlreadyExistsとなるため、既存ジョブとの一致を確認して処理します。完了済みという理由だけで新しい実行名を作ると、業務処理が重複します。AWS:StartExecution

入口のDLQは「開始できなかったジョブ」の隔離先です。開始済みワークフローの業務失敗とは分け、運用上の復旧方法も区別します。

同時実行は、起動Lambdaの数だけで管理できません。短時間で大量の長時間ジョブを開始できるからです。AgentCore・モデル・外部ツールのクォータを基に、実行中ジョブのスロットや投入レートを制御します。MapのMaxConcurrencyはそのMap内の制限なので、複数ワークフローを横断する全体制限が必要なら別途設計します。

監視ではDLQ件数に加え、受付から開始までの待ち時間、429率、UNKNOWN件数、完了時間、実行失敗、通知失敗を追います。jobId・executionArn・runtimeSessionIdを関連付けると原因を追いやすくなります。大きな入力や結果はS3に置き、状態には参照を渡します。

Redriveでは対象状態のRetry回数がリセットされます。ワークフローのRetry回数だけで費用を制御せず、ジョブ単位の総試行数・期限・モデル利用予算も保存してください。AWS:Redrive時のRetry動作

まとめ

導入時に優先するのは、Retryの回数を増やすことより、再実行しても安全な契約を作ることです。

  1. SQSは受付・配送、Step Functionsは業務工程を担当する。
  2. 一時障害だけを指数バックオフとジッターで再試行する。
  3. タイムアウトは結果不明として状態照合する。
  4. jobIdと操作IDで二重実行・二重更新を抑える。
  5. AgentCoreの完了はCallbackか状態照会で確認する。
  6. 回数・総時間・同時実行・費用の上限をジョブ全体で決める。

この設計を先に固めると、障害時にも安全に待ち、再試行し、必要に応じて運用へ引き継げる非同期バックエンドを作れます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?