この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
データアナリティクス事業本部の鈴木です。
Serverless Frameworkからスケジュール実行されるStep Functionsのステートマシンと、ステートマシンから呼び出されるLambda関数を作成することで、「定期的に実行され、失敗時には指定時間後にリトライされるLambda関数」を作ってみました。
やりたいこと
以前、『Lambdaをスケジュール実行して関数エラーが起きた際の再試行を確認してみた | DevelopersIO』でAmazon EventBridgeからスケジュール実行されるLambda関数についてご紹介しました。EventBridgeからの非同期呼び出しで関数エラーが起きた場合には、0〜2の設定した回数と、決められた数分程度の間隔でリトライが行われます。
もっとたくさんの回数や、長い間隔でリトライしたい場合は、別の方法を考える必要があります。
今回は、Step FunctionsのステートマシンがEventBridgeから呼び出せることに注目し、以下のような構成を試してみました。
データ基盤でのユースケースだと、複数のある程度時間がかかる取り込み処理が稼働しており、どれも動いていないときにLambda関数で簡単なチェック処理を行うような場合を想定しています。後に記載しているLambda関数の実装は、このケースを念頭に作成しています。
ツールの準備
今回はServerless Frameworkを使ってリソースを作成しました。
バージョンなどは以下になります。
- Serverless Framework
serverless --version # Framework Core: 2.43.1 (standalone) # Plugin: 5.1.3 # SDK: 4.2.2 # Components: 3.10.0
- Serverless Step Functionsプラグイン:3.5.1
やってみる
プロジェクトを作成する
まず、テンプレートを生成します。
※ 手順はServerless Frameworkで構築するStep Functions | DevelopersIOを参考にしました。
# プロジェクトを作成する。
serverless create --template aws-python3 --name StepFunctionsService --path TestStepFunctions
TestStepFunctionsディレクトリ配下は以下のようになっています。
tree -L 1
# .
# ├── handler.py
# └── serverless.yml
Step Functionsを利用するために、Serverless Step Functionsプラグインをインストールします。
# Serverless Step Functionsプラグインをインストールする。
cd TestStepFunctions/
npm install --save-dev serverless-step-functions
Lambda関数の修正
ステートマシンから起動するLambda関数を作成するため、handler.py
を修正します。
今回は以下のようなコードを用意しました。
import json
class NotCompletedException(Exception):
pass
def lambda_handler(event, context):
print("処理がまだ終わっていませんでした。例外を送出します。")
raise NotCompletedException
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
lambda_handler
関数では、3行目で定義しているNotCompletedException
をとりあえず送出するようになっています。実際は前提となる処理が終わっているか確認して、まだ終わっていない場合はこの例外を送出するイメージです。
serverless.ymlの修正
サービス全体の設定を行うためのファイルであるserverless.yml
を修正します。
スケジュール起動するステートマシンを作るため、以下のドキュメントを参考に修正しました。
完成したserverless.yml
はこちらです。
serverless.yml
service: cm-nayuts-StepFunctionsService
frameworkVersion: '2'
plugins:
- serverless-step-functions
provider:
name: aws
runtime: python3.8
region: ap-northeast-1
functions:
CMNayutsSampleFunction:
handler: handler.lambda_handler
stepFunctions:
stateMachines:
CMNayutsSampleStateMachine:
name: cm-nayuts-sample-StateMachine
events:
- schedule: cron(40 5 * * ? *)
definition:
StartAt: SampleInvocation
States:
SampleInvocation:
Type: Task
Resource:
Fn::GetAtt: [CMNayutsSampleFunction, Arn]
Retry:
- ErrorEquals:
- "NotCompletedException"
IntervalSeconds: 5
MaxAttempts: 3
BackoffRate: 2
End: true
ポイントはハイライトした箇所です。
まず、events
でスケジュール起動を設定しました。
また、Retry
にてLambda関数でNotCompletedException
(Lambda関数内で定義した自作の例外)が投げられた場合には、2回までリトライするようにしています。
※ Lambdaの関数の例外をステートマシンで受け取る方法は、以下のチュートリアルを参考にしました。
デプロイする
準備ができたので、リソースをデプロイします。
# デプロイする
sls deploy -v
CFnスタックが作成され、serverless.yml
で定義したリソースがデプロイされます。
起動を確認する
スケジュール起動を設定しているので、起動時間後に挙動を確認します。
Lambda関数で例外を送出しているので、ステータスは失敗になっています。
実行イベント履歴を確認すると、指定通り2回リトライされています。待ち時間はIntervalSeconds
が5秒で、BackoffRate
が2なので、指定通りの5秒と10秒になっていることが確認できます。
Lambdaのログを見ると、実装通りエラーが送出されていることが確認できました。
最後に
Serverless Frameworkからスケジュール実行されるStep Functionsのステートマシンと、ステートマシンから呼び出されるLambda関数を作成する方法を紹介しました。
試してみるまでは難しいイメージがありましたが、Serverless Frameworkを使うと手軽にLambdaとほかのサービスを組み合わせた仕組みがデプロイできるので良いですね。