Step Functions 内で発生したエラーのエラーハンドリングを実装する

Step Functions 内で発生したエラーのエラーハンドリングを実装する

はじめに

Step Functions 内の処理でエラーが発生したときに、特定の処理を行わせたいことがあると思います。 その際の取りうるパターンを整理します。

対象者

この記事は下記のような人を対象にしています。

  • Step Functions 内の処理でエラーが発生した時に、特定の処理を行わせたい人
  • ステートマシンでタスクフローを作成したい人

StepFunctions 内で完結させるパターン

タスクごとに Catch する

各タスクごとに Catch フィールドを使用することで、エラーをキャッチすることができます。 以下の図からも分かるように、冗長になっていて複雑なステートマシンになると、どういうフローかが視覚的に分かりにくくなります。

ASL はこちらです。

{
 "Comment": "A description of my state machine",
 "StartAt": "タスク1",
 "States": {
 "タスク1": {
 "Type": "Task",
 "Resource": "arn:aws:states:::glue:startJobRun",
 "Parameters": {
 "JobName": "myJobName1"
 },
 "Catch": [
 {
 "ErrorEquals": [
 "States.ALL"
 ],
 "Next": "エラー時の処理"
 }
 ],
 "Next": "タスク2"
 },
 "タスク2": {
 "Type": "Task",
 "Resource": "arn:aws:states:::glue:startJobRun",
 "Parameters": {
 "JobName": "myJobName2"
 },
 "Next": "タスク3",
 "Catch": [
 {
 "ErrorEquals": [
 "States.ALL"
 ],
 "Next": "エラー時の処理"
 }
 ]
 },
 "タスク3": {
 "Type": "Task",
 "Resource": "arn:aws:states:::glue:startJobRun",
 "Parameters": {
 "JobName": "myJobName3"
 },
 "Catch": [
 {
 "ErrorEquals": [
 "States.ALL"
 ],
 "Next": "エラー時の処理"
 }
 ],
 "End": true
 },
 "エラー時の処理": {
 "Type": "Task",
 "Resource": "arn:aws:states:::glue:startJobRun",
 "Parameters": {
 "JobName": "myErrorJob"
 },
 "End": true
 }
 }
}

Parallel ステートでまとめる

Parallel ステートを利用することで、Catch フィールドを一つにまとめることができます。 フロー図を見ても、先ほどと比べてすっきりしていて分かりやすい印象を受けます。

ASL はこちらです。

{
 "Comment": "A description of my state machine",
 "StartAt": "Parallel",
 "States": {
 "Parallel": {
 "Type": "Parallel",
 "Branches": [
 {
 "StartAt": "タスク1",
 "States": {
 "タスク1": {
 "Type": "Task",
 "Resource": "arn:aws:states:::glue:startJobRun",
 "Parameters": {
 "JobName": "myJobName"
 },
 "Next": "タスク2"
 },
 "タスク2": {
 "Type": "Task",
 "Resource": "arn:aws:states:::glue:startJobRun",
 "Parameters": {
 "JobName": "myJobName"
 },
 "Next": "タスク3"
 },
 "タスク3": {
 "Type": "Task",
 "Resource": "arn:aws:states:::glue:startJobRun",
 "Parameters": {
 "JobName": "myJobName"
 },
 "End": true
 }
 }
 }
 ],
 "End": true,
 "Catch": [
 {
 "ErrorEquals": [
 "States.ALL"
 ],
 "Next": "エラー時の処理"
 }
 ]
 },
 "エラー時の処理": {
 "Type": "Task",
 "Resource": "arn:aws:states:::glue:startJobRun",
 "Parameters": {
 "JobName": "myJobName"
 },
 "End": true
 }
 }
}

注意点

こちらのパターンには、すべてのエラーを捕捉できないという大きな注意点があります。 Catch 対象のエラーに”States.ALL”を指定しても States.Runtime エラーは捕捉することができません。そのため、States.Runtime エラーが発生する可能性がある場合は、別の方法を取る必要があります。

tates.ALL での再試行またはキャッチでは States.Runtime エラーは検出されません。

Step Functions のエラー処理 - AWS Step Functions

EventBridge を利用するパターン

2021年5月に、Step FunctionsとEventBridgeとのサービス統合がサポートされました。 これにより柔軟なエラー処理を行うことが可能になりました。例えばステートマシンのステータスの変化を検知して Lambda を呼び出すことなどが可能です。 以下は EventBrdige をトリガーととする Lambda 関数を SAM デプロイする際の YAML ファイルです。 参考:EventBridgeRule - AWS Serverless Application Model

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
 sam-app

 Sample SAM Template for sam-app

Globals:
 Function:
 Timeout: 3

Parameters:
 stateMachineArn:
 Type: String

Resources:
 HelloWorldFunction:
 Type: AWS::Serverless::Function 
 Properties:
 CodeUri: hello_world_function/
 Handler: hello_world/app.lambda_handler
 Runtime: python3.7
 Architectures:
 - x86_64
 Events:
 HelloWorld:
 Type: CloudWatchEvent 
 Properties:
 Pattern:
 source:
 - aws.status
 detail-type:
 - Step Functions Execution Status Change
 detail:
 status:
 - FAILED
 stateMachineArn:
 - !Ref stateMachineArn

Outputs:
 HelloWorldFunction:
 Description: "Hello World Lambda Function ARN"
 Value: !GetAtt HelloWorldFunction.Arn
 HelloWorldFunctionIamRole:
 Description: "Implicit IAM Role created for Hello World function"
 Value: !GetAtt HelloWorldFunctionRole.Arn

SAM デプロイに使用した TOML ファイルのサンプルです。

version = 0.1
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "sam-app"
s3_bucket = "{SAMアーティファクト用のS3バケット}"
s3_prefix = "sam-app"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
image_repositories = []
parameter_overrides = [
 "stateMachineArn={ステートマシンARN}}"
]

おわりに

本記事では、Step Functions 内の処理でエラーが発生したときに、特定の処理を行わせるアーキテクチャ案を紹介しました。この記事がどなたかの参考になれば幸いです。

参考