Step FunctionsでLambdaのエラータイプごとにエラーハンドリングするには?

記事タイトルとURLをコピーする

こんにちは!サービス開発部の布施です。

先日食べた牧場のソフトクリームがおいしすぎて忘れられません。

ということでアイコンがソフトクリームに似ているAWS Step FunctionsでAWS Lambdaのエラーハンドリングがどんな感じでできるのか、という内容をしたためていきたいと思います。

Step Functionsの概要

最初にStep Functionsの概要をざっくり紹介します。

Step Functionsには一番大きい単位としてState machinesが存在し、その中にStateと呼ばれる単位が存在します。

このStateにはいくつか種類があり、一番メジャーなものがTaskです。Task Stateは名前の通り単一の処理を行う単位ですね。例えば単一のLambda関数を呼び出したり、EC2インスタンスを起動したり、SNSで通知を送れたり、その他AWSサービスとの統合があったり…などなど。画像は3つのTask Stateが定義されており、全てLambda関数を呼び出していますね。

そしてTask Stateの設定欄を確認すると、「Error Handling」という項目があり、ここでTaskが失敗した場合の挙動を設定することが可能です。

Step Functionsのエラーハンドリング

もう少し細かくStep Functionsのエラーハンドリングについてみていきましょう。

まず、何もエラーハンドリングを設定しない状態でStep Functionsを実行すると、State machinesはエラーが発生したTask Stateで中断されます。今回は2つ目の「test2」というTask Stateから呼び出されたLambda関数でエラーを発生させてみました。

test2の後続のtest3は実行されない

ではLambda関数が失敗した場合に、メール処理をするようにエラーハンドリングをしてみましょう。Amazon SNSを使ってメールを送信する場合はこんなState machinesにできますね。

Catch #1は「こんなエラーだったらこんな風に処理する」という内容を設定する部分です。 「こんなエラー」の部分はマネジメントコンソールではStep Functions視点で選択ができます。ドキュメントにもStates.から始まるエラーとして一覧が載っています。

docs.aws.amazon.com

ところでLambdaのエラーは、以下の二つのエラータイプを設定することで基本的にキャッチできます。

  • States.ALL
  • States.TaskFailed

「基本的に」と書いたのはStates.Timeoutでも状況次第でキャッチできるためです。箇条で書いた2つでエラーがキャッチできることが本筋なので細かいことはここでは良しとしましょう。

なるほど、つまりStep FunctionsでLambdaハンドリングができるわけですね。めでたしめでたし。

...本当に??

LambdaのエラーごとにStep Functionsで制御する

Lambdaにはたくさんのエラーがあります。例えば

  • Lambda関数を呼び出すIAMポリシーがない
  • タイムアウトエラー
  • アプリケーション内でのエラー

などなど…. これらのLambdaのエラーごとにStep Functionsでエラーハンドリングを設定できないものでしょうか?

結論、できます。
マネジメントコンソールではプルダウンでStates.から始まるエラーのみが選択できるように見えますが、直接エラーメッセージを指定することが可能です。

もちろんマネジメントコンソールのCodeを選択して、LambdaのエラーメッセージをASL(Amazon State Langage)から指定することも可能です。 ASLはこれまでDesignで作成してきたState machinesの定義をJSONで表現したものです。 下記画像の通り、State > catch > ErrorEqualsのvalueにLambdaのエラーを記載します。

実際にやってみた

本当にLambdaのエラーでハンドリングできるのか検証の様子もお見せしましょう。 今回はテスト2で呼び出しているLambda関数の内部で例外を発生させます。 筆者の第一言語はRubyなのでraiseで明示的に例外を挙げます。

def lambda_handler(event:, context:)
    raise "HogeHoge"
end

このLambda関数のエラーはLambda.AWSLambdaExceptionになります。 これはLambda内部のエラーではなく、LambdaをAPIで呼び出したレスポンスのエラーなので注意してください。 Lambda内部のエラーは下記の通りでFunction<RuntimeError>となりますが、これではStep Functionsではcatchできないのです。

Response
{
  "errorMessage": "HogeHoge",
  "errorType": "Function<RuntimeError>",
  "stackTrace": [
    "/var/Task/lambda_function.rb:2:in `lambda_handler'",
    "/var/runtime/gems/aws_lambda_ric-3.0.0/lib/aws_lambda_ric/lambda_handler.rb:28:in `call_handler'",
    "/var/runtime/gems/aws_lambda_ric-3.0.0/lib/aws_lambda_ric.rb:88:in `run_user_code'",
    "/var/runtime/gems/aws_lambda_ric-3.0.0/lib/aws_lambda_ric.rb:66:in `start_runtime_loop'",
    "/var/runtime/gems/aws_lambda_ric-3.0.0/lib/aws_lambda_ric.rb:49:in `run'",
    "/var/runtime/gems/aws_lambda_ric-3.0.0/lib/aws_lambda_ric.rb:221:in `bootstrap_handler'",
    "/var/runtime/gems/aws_lambda_ric-3.0.0/lib/aws_lambda_ric.rb:203:in `start'",
    "/var/runtime/index.rb:4:in `<main>'"
  ]
}

では実際にエラーハンドリングの設定をしていきましょう。 今回は検証なのでエラーをキャッチしたらState machinesを正常に終了させるような動線にします。 エラーハンドリングでは直接State machinesを終了させる設定はできないので、一度PassというTaskを挟んでState machinesを終了させます。

では実行してみましょう。正常な動作ではエラーをキャッチしてState machinesは終了するはずです。

ちゃんとエラーをハンドリングしてState machinesは正常に終了しました。これでようやくめでたしめでたし。

終わりに

まとめです。

  • Step FunctionsでLambdaのエラーハンドリングが可能
  • States.から始めるStep Functionsのエラーを指定することでハンドリングできる
  • LambdaのAPIコールのエラーを直接指定するとより細かくハンドリングできる

この記事がStep Functionsを使おうとしているどなたかの役に立てば幸いです。

ふせ ゆきひろ(執筆記事の一覧)

サービス開発部 2022年新卒入社

好きな散歩エリアは谷中銀座です。