Java の AWS Lambda 関数エラー - AWS Lambda

Java の AWS Lambda 関数エラー

関数でエラーが発生すると、Lambda は呼び出し側にエラーの詳細を返します。Lambda が返すレスポンスの本文には、エラー名、エラータイプ、スタックフレームの配列を保存した JSON ドキュメントが含まれています。関数を呼び出したクライアントまたはサービスは、エラーを処理するか、エラーをエンドユーザーに渡すことができます。カスタム例外を使用して、クライアントエラーについてユーザーに役立つ情報を返すことができます。

src/main/java/example/HandlerDivide.java – ランタイム例外

import java.util.List; // Handler value: example.HandlerDivide public class HandlerDivide implements RequestHandler<List<Integer>, Integer>{ Gson gson = new GsonBuilder().setPrettyPrinting().create(); @Override public Integer handleRequest(List<Integer> event, Context context) { LambdaLogger logger = context.getLogger(); // process event if ( event.size() != 2 ) { throw new InputLengthException("Input must be an array that contains 2 numbers."); } int numerator = event.get(0); int denominator = event.get(1); logger.log("EVENT: " + gson.toJson(event)); logger.log("EVENT TYPE: " + event.getClass().toString()); return numerator/denominator; } }

関数が InputLengthException をスローすると、Java ランタイムはそれを以下のドキュメントにシリアル化します。

例 エラードキュメント (空白を追加)

{ "errorMessage":"Input must contain 2 numbers.", "errorType":"java.lang.InputLengthException", "stackTrace": [ "example.HandlerDivide.handleRequest(HandlerDivide.java:23)", "example.HandlerDivide.handleRequest(HandlerDivide.java:14)" ] }

この例では、InputLengthExceptionRuntimeException です。RequestHandlerインターフェイスはチェック済み例外を許可しません。RequestStreamHandler インターフェイスは IOException エラーのスローをサポートしています。

前の例の return ステートメントは、ランタイムの例外をスローすることもあります。

return numerator/denominator;

このコードは、算術エラーを返す可能性があります。

{"errorMessage":"/ by zero","errorType":"java.lang.ArithmeticException","stackTrace":["example.HandlerDivide.handleRequest(HandlerDivide.java:28)","example.HandlerDivide.handleRequest(HandlerDivide.java:13)"]}

エラー出力の表示

テストペイロードを渡して関数を呼び出し、Lambda コンソールで、コマンドラインから、または AWS SDK を使用して、エラー出力を表示できます。エラー出力は関数の実行ログにも記録され、トレースが有効になっている場合は AWS X-Ray にも記録されます。

Lambda コンソールでエラー出力を表示するには、テストイベントで呼び出します。

Lambda コンソールで関数を呼び出すには

  1. Lambda コンソール (関数ページ) を開きます。

  2. 関数を選択します。

  3. [Test (テスト)] ボタンの横にあるドロップダウンメニューから [Configure test events (テストイベントの設定)] を選択します。

    
            Lambda コンソールでテストイベントを設定する。
  4. 関数が処理するイベントに一致する [イベントテンプレート] を選択します。

  5. テストイベントの名前を入力し、必要に応じてイベント構造を変更します。

  6. [作成] を選択します。

  7. [Test] を選択します。

Lambda コンソールで、関数が同期的に呼び出され、結果が表示されます。レスポンス、ログ、その他の情報を表示するには、[Details (詳細)] セクションを展開します。

コマンドラインから関数を呼び出すと、AWS CLI はレスポンスを 2 つのドキュメントに分割します。発生した関数エラーを示すため、ターミナルに表示されるレスポンスには FunctionError フィールドが含まれます。関数によって返されたレスポンスまたはエラーは、出力ファイルに書き込まれます。

$ aws lambda invoke --function-name my-function out.json { "StatusCode": 200, "FunctionError": "Unhandled", "ExecutedVersion": "$LATEST" }

出力ファイルを表示して、エラードキュメントを確認します。

$ cat out.json {"errorMessage":"Input must contain 2 numbers.","errorType":"java.lang.InputLengthException","stackTrace": ["example.HandlerDivide.handleRequest(HandlerDivide.java:23)","example.HandlerDivide.handleRequest(HandlerDivide.java:14)"]}

また、Lambda は関数のログに最大 256 KB のエラーオブジェクトを記録します。コマンドラインから呼び出すときにログを表示するには、--log-type オプションを使用し、レスポンスで base64 文字列をデコードします。

$ aws lambda invoke --function-name my-function --payload "[100,0]" out.json --log-type Tail \ --query 'LogResult' --output text | base64 -d START RequestId: 081f7522-xmpl-48e2-8f67-96686904bb4f Version: $LATEST EVENT: [ 100, 0 ]EVENT TYPE: class java.util.ArrayList/ by zero: java.lang.ArithmeticException java.lang.ArithmeticException: / by zero at example.HandlerDivide.handleRequest(HandlerDivide.java:28) at example.HandlerDivide.handleRequest(HandlerDivide.java:13) END RequestId: 081f7522-xmpl-48e2-8f67-96686904bb4f REPORT RequestId: 081f7522-xmpl-48e2-8f67-96686904bb4f Duration: 4.20 ms Billed Duration: 100 ms Memory Size: 512 MB Max Memory Used: 95 MB XRAY TraceId: 1-5e73162b-1919xmpl2592f4549e1c39be SegmentId: 3dadxmpl48126cb8 Sampled: true

ログの詳細については、「Java の AWS Lambda 関数ログ作成」を参照してください。

エラーのタイプとソースについて

関数を呼び出すと、複数のサブシステムによってリクエスト、イベント、出力、レスポンスが処理されます。エラーは、Lambda サービス (呼び出しエラー) または関数のインスタンスから発生する可能性があります。関数エラーには、ハンドラーコードによって返される例外と、Lambda ランタイムによって返される例外があります。

Lambda サービスは呼び出しリクエストを受け取り、検証します。また、アクセス許可をチェックし、イベントドキュメントが有効な JSON ドキュメントであることを確認し、パラメータ値をチェックします。Lambda サービスはエラーを検出すると、例外のタイプとメッセージを返すほか、エラーの原因を示す HTTP ステータスコードも返します。

注記

Invoke API オペレーションから返される可能性のあるエラーの完全なリストについては、Lambda API リファレンスの「エラーの呼び出し」を参照してください。

Lambda サービスからの 4xx 番台のエラーは、リクエストの変更、アクセス許可のリクエスト、または再試行により、呼び出し元が修正できるエラーを示します。5xx 番台のエラーは、Lambda サービスの問題や、関数の設定またはリソースの問題を示します。これらの問題は、呼び出し元が解決することはできませんが、関数の所有者が修正できる可能性があります。

リクエストが検証に合格すると、Lambda はそのリクエストを関数のインスタンスに送信します。ランタイムは、イベントドキュメントをオブジェクトに変換し、ハンドラーコードに渡します。たとえば、ハンドラーメソッドの名前が関数の設定と一致しない場合、またはハンドラーコードがレスポンスを返す前に呼び出しがタイムアウトした場合、このプロセス中にエラーが発生する可能性があります。Lambda ランタイムエラーは、コードが返すエラーと同様の形式になりますが、ランタイムが返します。

以下の例では、ランタイムはイベントをオブジェクトに逆シリアル化できません。入力は有効な JSON タイプですが、ハンドラーメソッドの予期するタイプと一致しません。

例 Lambda ランタイムエラー

{ "errorMessage": "An error occurred during JSON parsing", "errorType": "java.lang.RuntimeException", "stackTrace": [], "cause": { "errorMessage": "com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of java.lang.Integer from String value '1000,10': not a valid Integer value\n at [Source: lambdainternal.util.NativeMemoryAsInputStream@35fc6dc4; line: 1, column: 1] (through reference chain: java.lang.Object[0])", "errorType": "java.io.UncheckedIOException", "stackTrace": [], "cause": { "errorMessage": "Can not construct instance of java.lang.Integer from String value '1000,10': not a valid Integer value\n at [Source: lambdainternal.util.NativeMemoryAsInputStream@35fc6dc4; line: 1, column: 1] (through reference chain: java.lang.Object[0])", "errorType": "com.fasterxml.jackson.databind.exc.InvalidFormatException", "stackTrace": [ "com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:55)", "com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:907)", ... ] } } }

Lambda ランタイムエラーおよびその他の関数エラーの場合、Lambda サービスはエラーコードを返しません。2xx 番台のステータスコードは、Lambda サービスがリクエストを受け入れたことを示します。エラーコードの代わりに、Lambda はレスポンスに X-Amz-Function-Error ヘッダーを含めることで、エラーを示します。

非同期呼び出しの場合、イベントは Lambda によって関数に送信される前にキューに入れられます。有効なリクエストの場合、Lambda は成功のレスポンスをすぐに返し、イベントをキューに追加します。次に、Lambda はキューからイベントを読み取り、関数を呼び出します。エラーが発生した場合、Lambda はエラーのタイプに応じて異なる動作で再試行します。詳細については、「非同期呼び出し」を参照してください。

クライアントでのエラー処理

Lambda 関数を呼び出すクライアントは、エラーを処理するか、エラーをエンドユーザーに渡すかを選択できます。正しいエラー処理動作は、アプリケーションの種類、対象ユーザー、エラーの原因によって異なります。たとえば、呼び出しがエラーコード 429 (リクエストが多すぎる) で失敗した場合、AWS CLI はユーザーにエラーを表示する前に最大 4 回再試行します。

$ aws lambda invoke --function-name my-function out.json An error occurred (TooManyRequestsException) when calling the Invoke operation (reached max retries: 4): Rate Exceeded.

その他の呼び出しエラーの場合、正しい動作はレスポンスコードによって異なります。5xx 番台のエラーは、ユーザーが何も対処しなくても解決できる一時的な状態を示している可能性があります。再試行は成功する場合もあれば失敗する場合もあります。429 以外の 4xx 番台のエラーは通常、リクエストでのエラーを示します。再試行が成功する可能性はほとんどありません。

関数エラーの場合、クライアントでは、エラードキュメントが処理され、ユーザーにわかりやすい形式でエラーメッセージが表示されます。ブラウザベースのアプリケーションでは、エラーメッセージとタイプが表示されますが、スタックトレースは省略されます。AWS CLI では、エラーオブジェクトが出力ファイルに保存され、代わりにレスポンスヘッダーから生成されたドキュメントが表示されます。

$ aws lambda invoke --function-name my-function --payload '[1000]' out.json { "StatusCode": 200, "FunctionError": "Unhandled", "ExecutedVersion": "$LATEST" }

例 out.json

{"errorMessage":"Input must be an array that contains 2 numbers.","errorType":"example.InputLengthException","stackTrace":["example.HandlerDivide.handleRequest(HandlerDivide.java:22)","example.HandlerDivide.handleRequest(HandlerDivide.java:13)"]}

他の AWS のサービスでのエラー処理

AWS のサービスが関数を呼び出すときは、呼び出しタイプと再試行動作を選択します。AWS のサービスは、リソースのライフサイクルイベントに応答して、またはユーザーからのリクエストを処理するために、スケジュールに従って関数を呼び出す場合があります。サービスによっては、関数を非同期に呼び出し、Lambda でエラーを処理する場合もあれば、再試行するか、ユーザーにエラーを返す場合もあります。

たとえば、API Gateway はすべての呼び出しエラーと関数エラーを内部エラーとして扱います。Lambda API が呼び出しリクエストを拒否した場合、API Gateway は 500 エラーコードを返します。関数が実行されてもエラーが返された場合、または誤った形式でレスポンスが返された場合、API Gateway は 502 エラーコードを返します。エラーレスポンスをカスタマイズするには、コードでエラーをキャッチし、レスポンスを必要な形式に加工する必要があります。

エラーの発生元とその原因を特定するには、AWS X-Ray を使用します。X-Ray を使用すると、エラーが発生したコンポーネントを見つけ、例外の詳細を確認できます。以下の例では、API Gateway から 502 レスポンスが返された関数エラーを示しています。


        API Gateway での関数エラーのトレースマップ。

関数に対してアクティブトレースを有効にすることで、X-Ray を開始します。

他のサービスがエラーを処理する方法の詳細については、他のサービスで AWS Lambda を使用する 章のトピックを参照してください。

サンプルアプリケーションでのエラー処理

このガイドの GitHub リポジトリには、エラーの使用方法を示すサンプルアプリケーションが含まれています。各サンプルアプリケーションには、簡易のデプロイとクリーンアップ用のスクリプト、AWS サーバーレスアプリケーションモデル (AWS SAM) テンプレート、サポートリソースが含まれています。

Java のサンプル Lambda アプリケーション

  • blank-java – Lambda の Java ライブラリ、ロギング、環境変数、レイヤー、AWS X-Ray トレース、単体テスト、および AWS SDK の使用を示す Java 関数。

  • java-basic – 単体テストと変数ログ記録設定を使用する、最小限の Java 関数。

  • java-events – Amazon API Gateway など、依存関係として AWS SDK を必要としないイベントタイプで、aws-lambda-java-events ライブラリを使用する最小限の Java 関数。

  • java-events-v1sdk – Amazon Simple Storage Service や Amazon DynamoDB、Amazon Kinesis など、依存関係として AWS SDK を必要とするイベントタイプで、aws-lambda-java-events ライブラリを使用する Java 関数。

  • s3-java – Amazon S3 からの通知イベントを処理し、Java Class Library (JCL) によりアップロード済みイメージファイルからサムネイルを作成する、Java 関数。

java-basic 関数には、カスタムランタイム例外を返すハンドラー (HandlerDivide) が含まれています。HandlerStream ハンドラーは RequestStreamHandler を実装し、IOException チェック済み例外をスローできます。