サーバーレスアプリケーションでエラーに対処する

AWS Step Functions と AWS Lambda を使用した場合

このチュートリアルでは、AWS Step Functions を使用してワークフローのランタイムエラーに対処する方法を説明します。AWS Step Functions はサーバーレスオーケストレーションサービスで、複数の Lambda 関数を連携させて柔軟なワークフローを作成し、デバッグや変更を簡単に行えるようにします。AWS Lambda は、サーバーのプロビジョニングや管理を行うことなく、コードを実行できるコンピューティングサービスです。 

Lambda 関数は、処理されない例外が発生した場合、指定したタイムアウトよりも長い時間実行された場合、メモリ不足が発生した場合などに失敗することがあります。API スロットリングまたはソケットのタイムアウトなどの状況に対処するため、Lambda 関数 1 つずつにエラー処理ロジックを記述して管理すると、作業に時間がかかり、特に分散アプリケーションでは作業が複雑になる可能性があります。このコードを各 Lambda 関数に埋め込むと関数間に依存関係が生まれます。変更に応じてこのすべての関係を管理することは難しい可能性があります。

このような状況を回避し、記述するエラー処理コードの量を減らすために、AWS Step Functions を使用して関数のエラー処理をサポートするサーバーレスワークフローを作成できます。エラーが開発者によって作成された関数の例外なのか (ファイルが見つからないなど)、それとも予測できないものであるのか (メモリ不足など) にかかわらず、Step Functions では、発生したエラーのタイプに基づく条件ロジックを使って応答できます。このようにワークフローロジックとビジネスロジックを分離することで、Lambda 関数のビジネスロジックを変更せずに、ワークフローでのエラーの処理方法を変更できます。

このチュートリアルでは、AWS Step Functions を使用して、このようなエラーを適切に処理するサーバーレスワークフローを設計し、実行します。RESTful API に模擬コールを行い、さまざまな応答コードと例外を返す AWS Lambda 関数を作成します。次に、AWS Step Functions を使用して、再試行機能とキャッチ機能を備え、発生した例外に応じてさまざまなロジックで応答するステートマシンを作成します。

このチュートリアルには AWS アカウントが必要です

AWS Step Functions と AWS Lambda に対する追加料金は発生しません。このチュートリアルで作成するリソースは無料利用枠の対象です。 

無料利用枠の詳細 >>


ステップ 1.API に模擬コールを行う Lambda 関数を作成する

このステップでは、API との基本的な対話を模擬的に行う Lambda 関数を作成します。この Lambda 関数では、イベントパラメータで入力として指定されたエラーコードに応じて例外を発生させ、架空の API からの応答をシミュレートします。


a.  [AWS マネジメントコンソール] を開きます。この作業手順ガイドは開いたままにしておいてください。この画面が読み込まれたら、ユーザー名とパスワードを入力して作業を開始します。検索バーに「Lambda」と入力し、[Lambda] を選択してサービスコンソールを開きます。

(クリックして拡大)


b.[関数の作成] を選択します。

(クリックして拡大)


c.[一から作成] が選択された状態のままにしておきます。次に、Lambda 関数を以下のように設定します。

[名前] に「MockAPIFunction」と入力します。
[ランタイム] で [Python 3.6] を選択します。
[ロール] で [カスタムロールの作成] を選択します。

新しい IAM ウィンドウが開きます。[ロール名] を「lambda_basic_execution」にしたままで、[Allow (許可)] をクリックします。Lambda コンソールが自動的に再度表示されます。

[関数の作成] をクリックします。

(クリックして拡大)


d.[MockAPIFunction] 画面で、[Function code (関数コード)] セクションまでスクロールします。このチュートリアルでは、Python で Lambda 関数を作成するためのプログラミングモデルを使用する関数を作成します。コードウィンドウで、すべてのコードを以下のコードに置き換え、[保存] を選択します。

class TooManyRequestsException(Exception): pass
class ServerUnavailableException(Exception): pass
class UnknownException(Exception): pass

def lambda_handler(event, context):
    statuscode = event["statuscode"]    
    if statuscode == "429":
        raise TooManyRequestsException('429 Too Many Requests')
    elif statuscode == "503":
        raise ServerUnavailableException('503 Server Unavailable')
    elif statuscode == "200":
        return '200 OK'
    else:
        raise UnknownException('Unknown error')

(クリックして拡大)


e.Lambda 関数が作成されたら、ウィンドウの上部にスクロールし、ページの右上に表示されている Amazon リソースネーム (ARN) を書き留めます。Amazon リソースネーム (ARN) によって AWS リソースを一意に識別できるため、AWS のサービスと API コール全体で AWS の項目とポリシーを追跡したり、使用したりできます。Step Functions から特定のリソースを参照する必要がある場合は、ARN が必要です。

(クリックして拡大)


ステップ 2:AWS Identity and Access Management (IAM) ロールを作成する

AWS Step Functions はコードを実行し、他の AWS リソース (Amazon S3 バケットに保存されたデータなど) にアクセスできます。セキュリティを維持するために、AWS Identity and Access Management (IAM) を使用して Step Functions にこれらのリソースへのアクセス権限を与える必要があります。


a.別のブラウザウィンドウで AWS マネジメントコンソールに移動し、検索バーに「IAM」と入力します。[IAM] をクリックしてサービスコンソールを開きます。

(クリックして拡大)


b.[ロール] をクリックして、[ロールの作成] を選択します。

(クリックして拡大)


c.[Select type of trusted entity (信頼済みエンティティタイプの選択)] ページの AWS のサービスリストから [Step Functions] を選択し、[Next: Permissions (次の手順: アクセス許可)] を選択します。

(クリックして拡大)


d.[Attached アクセス権限ポリシー] ページで、[次のステップ: 確認] をクリックします。

 

(クリックして拡大)


e.[確認] ページで [ロール名] に「step_functions_basic_execution」と入力し、[ロールの作成] をクリックします。

(クリックして拡大)


f.新しい IAM ロールが作成され、Lambda 関数の IAM ロールの下のリストに表示されます。

(クリックして拡大)


ステップ 3:Step Functions のステートマシンを作成する

API の模擬応答を実行する簡単な Lambda 関数を作成しました。次に、API を呼び出して例外を処理する Step Functions のステートマシンを作成します。

このステップでは、Step Functions コンソールを使用して、Retry フィールドと Catch フィールドが指定された Task 状態を使用して、さまざまな API 応答コードを処理するステートマシンを作成します。Task 状態を使用して模擬 API Lambda 関数を呼び出します。この関数によって、ステートマシンに入力として指定した API ステータスコードが返されます。


a.AWS Step Functions コンソールを開きます。[Create a state machine (ステートマシンの作成)] ページで [Author from scratch (一から作成)] を選択します。[Details (詳細)] セクションでステートマシンに MyAPIStateMachine という名前を付け、[I will use an existing role (既存のロールを使用する)] を選択します。

(クリックして拡大)


b.次に、模擬 API からの応答に応じてさまざまなアクションを実行するステートマシンを設計します。API にアクセスできない場合、ワークフローがもう一度実行されます。再試行は一時的なエラーに対応することに適しています。また、ワークフローでは模擬 API によってスローされるさまざまな例外を取得します。

[State machine definition (ステートマシンの定義)] セクションの内容を次のコードに置き換えます。

{
  "Comment": "An example of using retry and catch to handle API responses",
  "StartAt": "Call API",
  "States": {
    "Call API": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME",
      "Next" : "OK",
      "Comment": "Catch a 429 (Too many requests) API exception, and resubmit the failed request in a rate-limiting fashion.",
      "Retry" : [ {
        "ErrorEquals": [ "TooManyRequestsException" ],
        "IntervalSeconds": 1,
        "MaxAttempts": 2
      } ],
      "Catch": [ 
        {
          "ErrorEquals": ["TooManyRequestsException"],
          "Next": "Wait and Try Later"
        }, {
          "ErrorEquals": ["ServerUnavailableException"],
          "Next": "Server Unavailable"
        }, {
          "ErrorEquals": ["States.ALL"],
          "Next": "Catch All"
        }
      ]
    },
    "Wait and Try Later": {
      "Type": "Wait",
      "Seconds" : 1,
      "Next" : "Change to 200"
    },
    "Server Unavailable": {
      "Type": "Fail",
      "Error":"ServerUnavailable",
      "Cause": "The server is currently unable to handle the request."
    },
    "Catch All": {
      "Type": "Fail",
      "Cause": "Unknown error!",
      "Error": "An error of unknown type occurred"
    },
    "Change to 200": {
      "Type": "Pass",
      "Result": {"statuscode" :"200"} ,
      "Next": "Call API"
    },
    "OK": {
      "Type": "Pass",
      "Result": "The request has succeeded.",
      "End": true
    }
  }
}

(クリックして拡大)


c."Call API" Task 状態の "Resource" 行を見つけます (7 行目)。作成した模擬 API Lambda 関数の ARN にこの ARN を更新するには、ARN のテキストをクリックし、リストから ARN を選択します。

(クリックして拡大)


d.ビジュアルワークフローペインの横にある更新ボタンをクリックすると、設計したワークフローに対応するステートマシンの図が Step Functions によって作成されます。ビジュアルワークフローを確認し、[Create state machine (ステートマシンの作成)] をクリックします。

(クリックして拡大)


ステップ 4.エラー処理ワークフローをテストする

エラー処理ワークフローをテストするために、入力としてエラーコードを指定してステートマシンを呼び出し、模擬 API を呼び出します。


a.[Start execution (実行の開始)] をクリックします。

(クリックして拡大)


b.[New execution (新しい実行)] ダイアログボックスが表示され、ステートマシンへの入力を指定できます。ユーザーが API の部分を担当し、模擬 API によって返してもらいたいエラーコードを指定します。既存のテキストを以下のコードに置き換え、[Start execution (実行の開始)] を選択します。

{
    "statuscode": "200"
}

(クリックして拡大)


c.[Execution details (実行の詳細)] 画面で [Input (入力)] をクリックし、ステートマシンに指定した入力を確認します。[Output (出力)] をクリックしてステートマシンの実行結果を確認します。ステータスコード 200 がワークフローによって API コールの成功として解釈されたことを確認できます。

(クリックして拡大)


d.[Visual workflow (ビジュアルワークフロー)] で、各実行の実行パスを確認できます。このパスはワークフローでは緑色で示されます。"Call API" Task 状態をクリックすると、[Step details (ステップの詳細)] 画面で [Input (入力)] フィールドと [Output (出力)] フィールドが展開されます。

この Task 状態によって、指定した入力を使用して模擬 API Lambda 関数が正常に呼び出され、その Lambda 関数の出力 "200 OK" が取得されたことを確認できます。

(クリックして拡大)


e.ビジュアルワークフローの "OK" Task 状態をクリックします。[Step details (ステップの詳細)] で、前のステップの出力 (Call API Task 状態) が、このステップへの入力として渡されたことを確認できます。OK 状態は Pass 状態で、この状態では何も作業せずに入力を出力に渡します。Pass 状態は、ステートマシンを構築およびデバッグするときに便利です。

(クリックして拡大)


ステップ 5.ステートマシンの実行を検証する


a.[Execution details (実行の詳細)] 画面の上部までスクロールし、[MyAPIStateMachine] をクリックします。

(クリックして拡大)


b.[Start execution (実行の開始)] をもう一度クリックします。今回は以下の入力を指定して [Start execution (実行の開始)] をクリックします。

{
    "statuscode": "503"
}

(クリックして拡大)


c.[Execution event history (実行イベント履歴)] セクションで、各実行ステップを展開してワークフローの動作が想定どおりであることを確認します。この実行は失敗すると想定しているため、驚かないでください。 以下のプロセスが実行されたことがわかります。

  1. Step Functions によって入力が取得された
  2. その入力が Call API Task 状態に渡された
  3. Call API Task 状態によってこの入力が使用され、MockAPIFunction が呼び出された
  4. MockAPIFunction が実行された
  5. MockAPIFunction が ServerUnavailableException で失敗した
  6. Call API Task 状態の catch ステートメントによってこの実行が取得された
  7. catch ステートメントでワークフローを完了できなかった
  8. ステートマシンが実行を完了した

(クリックして拡大)


d.429 例外のシミュレーションを行います。[Execution details (実行の詳細)] 画面の上部までスクロールし、[MyAPIStateMachine] をクリックします。[Start execution (実行の開始)] をもう一度クリックします。以下の入力を指定して [Start execution (実行の開始)] をクリックします。

{
    "statuscode": "429"
}

(クリックして拡大)


e.ワークフローの再試行動作を検証します。[Execution event history (実行イベント履歴)] セクションで各実行ステップをもう一度展開し、Step Functions によって MockAPILambda 関数がもう 2 回呼び出されていることを確認します。この呼び出しは両方とも失敗しています。この時点では、ワークフローは、API が一時的に応答していないだけと考えて、Wait and Try Later 状態 (右側の画像に表示) に遷移します。

次に、Wait 状態によって強制的に応答コードが 200 に変更されるため、ワークフローは実行を正常に完了できます。これは実際のアプリケーションでは、429 例外を処理するために使用しない方法ですが、チュートリアルであるため、簡単にしています。

(クリックして拡大)


f.ワークフローのインスタンスをもう一度実行します。今回は、ステートマシンによって処理されないランダムな API 応答を指定します。

{
    "statuscode": "999"
}

[Execution event history (実行イベント履歴)] を使用して実行を再び検証します。完了したら、[MyAPIStateMachine] をもう一度クリックします。[Executions (実行)] ペインでは、ワークフローのすべての実行履歴を確認し、必要に応じて個別にステップインできます。

(クリックして拡大)


ステップ 6.リソースを終了する

このステップでは、AWS Step Functions と AWS Lambda の関連リソースを終了します。

重要: あまり使用されていないリソースを終了することは、コストを削減するためのベストプラクティスです。リソースを終了しないと、料金が発生する場合があります。


a.AWS Step Functions コンソールウィンドウの上部で [ステートマシン] をクリックします。

(クリックして拡大)


b.[State machines (ステートマシン)] ウィンドウで [MyAPIStateMachine] をクリックし、[Delete (削除)] をクリックします。ダイアログボックスで [Delete state machine (ステートマシンの削除)] を選択し、アクションを承認します。処理中の実行がすべて完了したことが Step Functions により確認されると、1~2 分でステートマシンが削除されます。

(クリックして拡大)


c.次に、Lambda 関数を削除します。AWS マネジメントコンソールのメニューで [サービス] をクリックしてから、[Lambda] を選択します。

(クリックして拡大)


d.[関数] 画面で [MockAPIFunction] をクリックし、[アクション]、[削除] の順に選択します。もう一度 [削除] をクリックして削除を確認します。

(クリックして拡大)


e.最後に、IAM ロールを削除します。AWS マネジメントコンソールのメニューで [サービス] をクリックしてから、[IAM] を選択します。

(クリックして拡大)


f.このチュートリアル用に作成した IAM ロールを両方とも選択し、[ロールの削除] をクリックします。ダイアログボックスで [はい、削除します] をクリックして削除を承認します。


これで、AWS マネジメントコンソールからサインアウトすることができます。

(クリックして拡大)


お疲れ様でした。

AWS Step Functions と AWS Lambda を使用してネットワーク API のエラー処理ワークフローを作成できました。AWS Lambda を使用すれば、実質どのようなタイプのアプリケーションやバックエンドサービスでも管理を必要とせずにコードを実行できます。コードさえアップロードすれば、高可用性を実現しつつコードを実行およびスケーリングするために必要なことはすべて Lambda により行われます。

AWS Step Functions と AWS Lambda を組み合わせることで、AWS Lambda 関数のサーバーレスアプリケーション向けの調整が簡単になります。Step Functions を使用すると、基盤となるアプリケーションによって状態を管理したり調整したりしなくても、Lambda 関数を使用して複雑なワークフローを制御できます。Step Functions は、Amazon EC2 や Amazon ECS といったコンピューティングリソースを使用したマイクロサービスの調整にも使えます。

AWS Step Functions について調べる

ドキュメントの詳細