こんにちは、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 のアップデートで maxDelay
と jitterStrategy
が追加されています。
プロパティ名 | 説明 | デフォルト値 |
---|---|---|
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 秒です。既定は未設定となります。
LambdaInvoke
でretryOnServiceExceptions
をfalse
とすることにより既定で設定されるリトライオプションを無効にし、リトライオプションの二重設定を防いでいます。
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,
});
jitterStrategy
でFULL
を指定すると、リトライオプションでジッターを有効にできます。既定は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 を見つけられたので結果としてスマートな実装を行うことができました。
以上 |