[AWS CDK] AWS Step Functions の再試行オプションで MaxDelay と Jitter を実装してみた

2023.10.09

こんにちは、CX 事業本部 Delivery 部の若槻です。

先月に AWS Step Functions で、エラー発生時の再試行オプションのアップデートがありました。

すでに DevelopersIO でも紹介ブログがアップされていますが、再試行オプションに MaxDelay および Jitter プロパティが追加されたアップデートとなります。

この Step Functions の再試行オプションですが、AWS CDK でも v2.95.0 で実装されていたので、今回試してみました。

stepfunctions: properties for ErrorPath, CausePath, MaxDelay, Jitter (#27051) (dfe29ce)

RetryProps で指定できるプロパティ

AWS CDK(TypeScript)のドキュメントで、RetryProps を見てみます。

RetryProps で指定できるプロパティは以下の通りです。v2.95.0 のアップデートで maxDelayjitterStrategy が追加されています。

プロパティ名 説明 デフォルト値
errors 再試行するエラーのリスト 全てのエラー
interval 再試行するまでの待機時間 1 秒
maxAttempts 再試行する回数 3 回
backoffRate 指数バックオフの待機時間をどれだけ長くするか 2
jitterStrategy 指数バックオフの待機時間にランダム性を持たせるかどうか なし
maxDelay 指数バックオフの最大待機時間 なし

試してみた

Lambda 関数を実行するタスクで試してみます。

最大遅延時間

まずは最大遅延時間を試してみます。AWS CDK で次の実装を行います。

lib/cdk-sample-stack.ts

import {
  aws_stepfunctions,
  aws_stepfunctions_tasks,
  aws_lambda,
  Stack,
  StackProps,
  Duration,
  CfnOutput,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    const invokeLambdaTask = new aws_stepfunctions_tasks.LambdaInvoke(
      this,
      'InvokeLambdaTask',
      {
        lambdaFunction: new aws_lambda.Function(this, 'Func', {
          handler: 'index.handler',
          runtime: aws_lambda.Runtime.NODEJS_18_X,
          architecture: aws_lambda.Architecture.ARM_64,
          code: aws_lambda.Code.fromInline(
            'exports.handler = async () => { throw new Error(); };'
          ),
        }),
        retryOnServiceExceptions: false,
      }
    );

    invokeLambdaTask.addRetry({
      errors: ['States.ALL'],
      maxAttempts: 5,
      maxDelay: Duration.seconds(5),
    });

    const stateMachine = new aws_stepfunctions.StateMachine(
      this,
      'StateMachine',
      {
        definition: invokeLambdaTask,
      }
    );

    new CfnOutput(this, 'StateMachineArn', {
      value: stateMachine.stateMachineArn,
    });
  }
}

  • addRetry を使うと aws_stepfunctions_tasks のタスククラスにリトライを設定できます。
    • maxDelay で最大遅延時間を設定できます。今回は 5 秒です。既定は未設定となります。
  • LambdaInvokeretryOnServiceExceptionsfalse とすることにより既定で設定されるリトライオプションを無効にし、リトライオプションの二重設定を防いでいます。

CDK デプロイして作成されたステートマシンの定義を確認すると、次のように MaxDelaySeconds が設定されています。

$ aws stepfunctions describe-state-machine --state-machine-arn $stateMachineArn --query "definition" --output text | jq -r .
{
  "StartAt": "InvokeLambdaTask",
  "States": {
    "InvokeLambdaTask": {
      "End": true,
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "MaxAttempts": 5,
          "MaxDelaySeconds": 5
        }
      ],
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:CdkSampleStack-Func217E03A4-e7TETQbcSnPT",
        "Payload.$": "$"
      }
    }
  }
}

ステートマシンを実行した際のイベント一覧が以下になります。

TaskFailed とその次回の TaskStarted の間隔を表にしたのが以下です。

試行回数 試行時間 試行間隔
1 0.313 -
2 1.387 1.074
3 3.628 2.241
4 7.836 4.208
5 13.059 5.223
6 18.270 5.211

5 回目の試行以降では試行間隔が指数関数的に増えず、5 秒固定となっています。最大遅延時間の動作を確認できました。

ジッター

次にジッターを試してみます。AWS CDK で次の実装を行います。addRetry 以外の記述は最大遅延時間のときと同じです。

lib/cdk-sample-stack.ts

    invokeLambdaTask.addRetry({
      errors: ['States.ALL'],
      maxAttempts: 5,
      jitterStrategy: aws_stepfunctions.JitterType.FULL,
    });

  • jitterStrategyFULL を指定すると、リトライオプションでジッターを有効にできます。既定は NONE です。

CDK デプロイして作成されたステートマシンの定義を確認すると、次のように JitterStrategy が設定されています。

$ aws stepfunctions describe-state-machine --state-machine-arn $stateMachineArn --query "definition" --output text | jq -r .
{
  "StartAt": "InvokeLambdaTask",
  "States": {
    "InvokeLambdaTask": {
      "End": true,
      "Retry": [
        {
          "ErrorEquals": [
            "States.ALL"
          ],
          "MaxAttempts": 5,
          "JitterStrategy": "FULL"
        }
      ],
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Parameters": {
        "FunctionName": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:CdkSampleStack-Func217E03A4-e7TETQbcSnPT",
        "Payload.$": "$"
      }
    }
  }
}

ステートマシンを実行した際のイベント一覧が以下になります。

TaskFailed とその次回の TaskStarted の間隔を表にしたのが以下です。

試行回数 試行時間 試行間隔
1 0.478 -
2 0.676 0.198
3 1.919 1.243
4 3.176 1.257
5 10.430 7.254
6 22.777 12.347

試行間隔の増加が指数関数的となっておらず、ランダムとなっています。ジッターの動作を確認できました。

おわりに

AWS CDK で AWS Step Functions の再試行オプションで MaxDelay と Jitter を実装してみました。

はじめ retryOnServiceExceptions オプションの存在を知らず、リトライオプションを二重に設定しないためにはエスケープハッチや CallAwsService が必要だと考えていましたが、検証時に retryOnServiceExceptions を見つけられたので結果としてスマートな実装を行うことができました。

以上 |