Lambda 再帰ループ検出を使用した無限ループの防止 - AWS Lambda

Lambda 再帰ループ検出を使用した無限ループの防止

関数を呼び出すのと同じサービスまたはリソースに出力するように Lambda 関数を設定すると、無限再帰ループが作成される可能性があります。例えば、Lambda 関数が Amazon Simple Queue Service (Amazon SQS) キューにメッセージを書き込み、その書き込まれたキューによって同じ関数が呼び出される場合があります。この呼び出しにより、関数はキューに別のメッセージを書き込み、キューによって関数が再び呼び出されます。

意図しない再帰ループが発生すると、AWS アカウント に予期しない料金が請求される可能性があります。ループが原因で Lambda がスケールし、アカウントで利用可能なすべての同時実行性が使用されることもあります。意図しないループの影響を減らすために、Lambda は特定のタイプの再帰ループを発生後すぐに検出することができます。Lambda が再帰ループを検出すると、関数の呼び出しを停止し、ユーザーに通知します。

意図的に再帰パターンを使用するようデザインされている場合は、Lambda 再帰ループ検出の無効化をリクエストできます。この変更をリクエストするには、AWS Support にお問い合わせください

重要

Lambda 関数を使用して意図的に AWS 関数を呼び出すのと同じリソースにデータを書き戻すように設計している場合は、AWS アカウント に予期しない料金が請求されないように注意し、適切なガードレールを実装してください。再帰呼び出しパターンを使用する際のベストプラクティスの詳細については、Serverless Land の「Lambda 関数が暴走する原因となる再帰パターン」を参照してください。

再帰ループ検出を理解する

Lambda の再帰ループ検出は、イベントを追跡することで動作します。Lambda はイベント駆動型のコンピューティングサービスで、特定のイベントが発生すると関数コードを実行します。例えば、アイテムが Amazon SQS キューまたは Amazon Simple Notification Service (Amazon SNS) トピックに追加された場合などが挙げられます。Lambda は、システム状態の変化に関する情報を含んだイベントを JSON オブジェクトとして関数に渡します。イベントによって関数が実行されるとき、これを呼び出しと呼びます。

再帰ループを検出するために、Lambda は AWS X-Ray トレースヘッダーを使用します。再帰ループ検出をサポートしている AWS のサービス が Lambda にイベントを送信すると、それらのイベントには自動的にメタデータの注釈が付けられます。Lambda 関数がこれらのイベントの 1 つを、サポートされている別の AWS のサービス に対してサポートされているバージョンの AWS SDK を使用して書き込むと、このメタデータが更新されます。更新されたメタデータには、イベントによって関数が呼び出された回数が含まれます。

注記

この機能を動作させるのに、X-Ray アクティブトレーシングを有効にする必要はありません。再帰ループ検出は、AWS をお使いのすべてのお客様に対してデフォルトでオンになっています。この機能は無料で使用できます。

リクエストチェーンとは、同じトリガーイベントによって発生する Lambda 呼び出しのシーケンスです。例えば、ある Amazon SQS キューが Lambda 関数を呼び出すとします。呼び出された Lambda 関数は、次に、処理されたイベントを同じ Amazon SQS キューに送り返し、そこで関数が再度呼び出されます。この例では、それぞれの関数呼び出しは同じリクエストチェーンに分類されます。

同じリクエストチェーンで関数が 16 回を超えて呼び出された場合、Lambda はそのリクエストチェーン内の次の関数呼び出しを自動的に停止し、ユーザーに通知します。関数が複数のトリガーで構成されている場合、他のトリガーからの呼び出しには影響しません。

注記

ソースキューの再処理ポリシーの maxReceiveCount 設定が 16 より大きい場合、Lambda 再帰保護は、再帰ループが検出され終了された後に Amazon SQS がメッセージを再試行することを防止しません。Lambda は、再帰ループを検出し、それ以降の呼び出しを中止すると、イベントソースマッピングに RecursiveInvocationException を返します。メッセージの receiveCount 値を増加します。Amazon SQS が maxReceiveCount の超過を判定して設定されたデッドレターキューにメッセージを送信するまで、Lambda はメッセージを再試行し続け、関数の呼び出しをブロックし続けます。

障害発生時の宛先またはデッドレターキューが関数に設定されている場合、Lambda はその停止した呼び出しからのイベントを指定された宛先またはデッドレターキューにも送信します。関数に宛先またはデッドレターキューを設定する場合は、関数がイベントトリガーまたはイベントソースマッピングとしても使用する Amazon SNS トピックまたは Amazon SQS キューを使用しないようにしてください。関数を呼び出すのと同じリソースにイベントを送信すると、別の再帰ループを作成できます。

サポートされている AWS のサービス および SDK

Lambda が検出できるのは、サポートされている特定の AWS のサービス を含む再帰ループのみです。再帰ループを検出するには、関数はサポートされている AWS SDK のいずれかを使用する必要もあります。

サポートされている AWS のサービス

Lambda は現在、関数、Amazon SQS、Amazon SNS の間の再帰ループを検出します。Lambda は、Lambda 関数のみで構成されるループも検出します。これらの関数は、同期的に、または非同期的にお互いを呼び出す可能性があります。次の図に、Lambda が検出できるループの例を示します。

Lambda 関数、Amazon SNS、Amazon SQS キュー間の再帰ループの図。

Amazon DynamoDB や Amazon Simple Storage Service (Amazon S3) などの別の AWS のサービス がループの一部を形成してる場合、現時点では Lambda はそのループを検出して停止することはできません。

現時点では、Lambda は Amazon SQS と Amazon SNS に関連する再帰ループのみを検出するため、他の AWS のサービス が関与するループによって Lambda 関数が意図しない形で使用される可能性があります。

ユーザーの AWS アカウント に予期しない料金が請求されるのを防ぐため、Amazon CloudWatch アラームを設定して、通常とは異なる使用パターンが警告されるようにすることをお勧めします。例えば、Lambda 関数の同時実行数や呼び出し回数の急増が検知された場合に、CloudWatch を設定しておくとユーザーに通知が送信されます。また、請求アラームを設定しておくことで、アカウントでの支出が指定したしきい値を超えたときにも通知を受け取ることができます。AWS Cost Anomaly Detection を使用すると、通常とは異なる請求パターンがあった場合に警告を受け取ることができます。

サポートされている AWS SDK

Lambda が再帰ループを検出するには、関数で次のバージョンまたはそれ以降の SDK を使用する必要があります。

ランタイム 最低限必要な AWS SDK バージョン

Node.js

2.1147.0 (SDK バージョン 2)

3.105.0 (SDK バージョン 3)

Python

1.24.46 (boto3)

1.27.46 (botocore)

Java 8 および Java 11

1.12.200 (SDK バージョン 1)

2.17.135 (SDK バージョン 2)

Java 17

2.20.81

Java 21

2.21.24

.NET

3.7.293.0

Ruby

3.134.0

PHP

3.232.0

Python や Node.js などの一部の Lambda ランタイムには、あるバージョンの AWS SDK が含まれています。関数のランタイムに含まれている SDK のバージョンが必要最低限よりも低い場合は、サポートされているバージョンの SDK を関数のデプロイパッケージに追加することができます。Lambda レイヤーを使用して、サポートされている SDK バージョンを関数に追加することもできます。各 Lambda ランタイムに含まれている SDK のリストについては、Lambda ランタイム を参照してください。

Lambda 再帰検出は Lambda Go ランタイムではサポートされていません。

再帰ループ通知

Lambda が再帰ループを停止すると、AWS Health Dashboard やメールで通知が届きます。CloudWatch メトリクスを使用して、Lambda が停止した再帰呼び出しの数をモニタリングすることもできます。

AWS Health Dashboard の通知

Lambda が再帰呼び出しを停止すると、AWS Health Dashboard は、[アカウントヘルス] ページの [未解決の問題と最近の問題] に通知を表示します。Lambda が再帰呼び出しを停止してからこの通知が表示されるまでに、最大 3 時間かかる場合があることに注意してください。AWS Health Dashboard でのアカウントイベントの表示の詳細については、AWS Health ユーザーガイドの「AWS Health ダッシュボードの使用開始 — アカウントの正常性」を参照してください。

E メールアラート

Lambda が関数の再帰呼び出しを初めて停止すると、E メールアラートが送信されます。Lambda は、AWS アカウント の各関数につき 24 時間ごとに最大 1 通のメールを送信します。Lambda から E メール通知が送信された後の 24 時間は、Lambda によって関数の再帰呼び出しが再度停止された場合でも、その関数に関するメールが届きません。Lambda が再帰呼び出しを停止してからこの E メールアラートを受信するまでに、最大 3 時間かかる場合があることに注意してください。

再帰的なループに関する E メールアラートは、Lambda からお客様の AWS アカウント のプライマリアカウント連絡先と代替オペレーション連絡先に送信されます。アカウントのメールアドレスの表示または更新については、AWS 全般のリファレンスの「連絡先情報の更新」を参照してください。

Amazon CloudWatch メトリクス

CloudWatch メトリクスの RecursiveInvocationsDropped には、1 回のリクエストチェーンで関数が 16 回を超えて呼び出されたために Lambda が停止した関数の呼び出し回数が記録されます。Lambda は再帰呼び出しを停止するとすぐにこのメトリクスを出力します。このメトリクスを表示するには、「CloudWatch コンソールでメトリクスを表示する」に記載の指示に従い、メトリクス RecursiveInvocationsDropped を選択します。

再帰ループ検出通知への対応

同じトリガーイベントによって関数が 16 回を超えて呼び出された場合、Lambda はそのイベントの次の関数呼び出しを停止して再帰ループを中断します。Lambda が中断した再帰ループの再発を防ぐには、以下を実行してください。

  • 関数が同時に実行できる回数を 0 に減らすと、以降の呼び出しがすべてスロットリングされます。

  • 関数を呼び出すトリガーやイベントソースマッピングを削除または無効にします。

  • 関数を呼び出している AWS リソースにイベントを書き戻すコードを特定し、欠陥を修正します。よくある不具合の原因として、変数を使用して関数のイベントソースとターゲットを定義している場合が挙げられます。両方の変数に同じ値が使用されていないことを確認してください。

さらに、Lambda 関数のイベントソースが Amazon SQS キューの場合は、ソースキューにデッドレターキューを設定することを検討してください。

注記

Lambda 関数ではなく、ソースキューのデッドレターキューを設定するようにしてください。関数で設定したデッドレターキューは、イベントソースキューではなく、関数の非同期呼び出しキューに使用されます。

イベントソースが Amazon SNS トピックの場合は、関数に障害発生時の宛先を追加することを検討してください。

関数で利用できる同時実行数をゼロにするには (コンソール)
  1. Lambda コンソールの [関数ページ] を開きます。

  2. 関数の名前を選択します。

  3. [スロットル] を選択します。

  4. [関数のスロットル] ダイアログボックスで、[確認] を選択します。

関数のトリガーまたはイベントソースマッピングを削除するには (コンソール)
  1. Lambda コンソールの [関数ページ] を開きます。

  2. 関数の名前を選択します。

  3. [Configuration] タブを選択し、[Triggers] を選択します。

  4. [Triggers] で、削除するトリガーまたはイベントソースマッピングを選択し、[Delete] を選択します。

  5. [トリガーの削除] ダイアログボックスで、[削除] を選択します。

関数のイベントソースマッピングを無効にするには (AWS CLI)
  1. 無効にするイベントソースマッピングの UUID を見つけるには、AWS Command Line Interface (AWS CLI) の list-event-source-mappings コマンドを実行します。

    aws lambda list-event-source-mappings
  2. イベントソースマッピングを無効にするには、次の AWS CLI update-event-source-mapping コマンドを実行します。

    aws lambda update-event-source-mapping --function-name MyFunction \ --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 --no-enabled