この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
AWS Step Functionsでもイレギュラーケースに対応したい
こんにちは、のんピ(@non____97)です。
皆さんはジョブ管理システムから抜け出したいと思ったことはありますか? 私は常に思っています。
普段は定期実行しているジョブネットでも、「休日の時は実行しないで欲しい」というケースがあると思います。また、「普段は実行しないけど、締め日だけ実行して欲しい」といったケースもあるでしょう。このようなイレギュラーなケースをEventBridgeのCrons式で表現することは難しいです。
しかし、そのような場合でもAWS Step FunctionsとAWS Systems Manager Change Calendar(以降SSM Change Calendar)を連携すれば対応できるんです。
今回はジョブ管理システムをAWS Step Functionsに置き換えることを想定して、定期実行処理のイレギュラーケースに対応してみます。
いきなりまとめ
- AWS Step FunctionsとAWS Systems Manager Change Calendarを連携すれば、Cron式では表現しづらいイレギュラーケースにも対応できる
AND
やOR
で複数のSSM Change Calendarを組み合わせて条件を決めたい場合は、以下のように設定するAND
:GetCalendarState
APIのCalendarNames
パラメーターに複数のSSM Change CalendarのARNを指定するOR
:Pararell
でGetCalendarState
APIを並列で呼び出し、後続のChoice
でGetCalendarState
APIの結果を評価する
検証の概要
SSM Change Calendarは柔軟な定期処理実行を実現するための機能です。
今回は以下2つのパターンのイレギュラーな定期実行処理を、AWS Step FunctionsとSSM Change Calendarを用いて表現してみます。
- 締め日であれば処理を実行する
- 祝日であれば処理を実行しない
AWS Step FunctionsとSSM Change Calendarの連携方法は、ステートマシンからSSM Change Calendarの GetCalendarState APIを呼び出し、その結果がOPEN
かCLOSED
かで判断します。
OPEN
であれば後続の処理を実行し、CLOSED
であれば後続の処理をスキップします。
やってみた
SSM Change Calendarの作成
まずは、SSM Change Calendarを作成します。カレンダーは締め日用と祝日用の2つ用意します。
締め日用のカレンダーは「締め日であれば処理を実行する」ためのカレンダーです。祝日用のカレンダーは「祝日であれば処理を実行しない」ためのカレンダーです。
締め日用のカレンダーから作成します。
Systems Managerのコンソールからカレンダーの変更
- カレンダーを作成
をクリックします。
次に、カレンダーの名前と説明、カレンダータイプを選択し、カレンダーを作成
をクリックします。
カレンダータイプはDEFAULT_OPEN
とDEFAULT_CLOSED
とがあり、以下のように使い分けます。
- 指定した日に実行させたくないのであれば
DEFAULT_OPEN
を選択 - 指定した日に実行させたいのであれば
DEFAULT_CLOSED
を選択
締め日用のカレンダーは「締め日であれば処理を実行する」ためのカレンダーなので、カレンダータイプはDEFAULT_CLOSED
を選択します。
カレンダーを作成
をクリックすると、何もイベントの入っていない、まっさらなカレンダーが作成されます。
それでは締め日をイベントとして追加します。イベントの追加はイベントを作成
をクリックします。
イベント名やイベントスケジュール、タイムゾーンを設定して、予定されたイベントを作成
をクリックします。
今回は12/23を締め日として指定しました。
予定されたイベントを作成
をクリックすると、カレンダーの12/23にSettlement Closing Date
という締め日を表すイベントが追加されていることを確認できます。
祝日用のカレンダーも同様に作成します。「祝日であれば処理を実行しない」ためのカレンダーであるため、カレンダータイプはDEFAULT_OPEN
を選択しました。
祝日は12/23として指定しました。
なお、今回はイベントを手動で登録しましたが、以下記事で紹介している通り、GoogleカレンダーやOutlookカレンダーなどで祝日や締め日のカレンダーを用意して、SSM Change Calendarにカレンダーのicsファイルをインポートすることでイベントを追加することもできます。
ステートマシンの作成
締め日用カレンダーの動作確認で使うステートマシン
次にステートマシンを作成します。
まずは締め日用カレンダーの動作確認で使うステートマシンから作成します。
先頭のタスクで GetCalendarState APIを呼び出し、締め日用カレンダーを参照します。
GetCalendarState
API実行後は、OPEN
かCLOSED
かを判定するためにChoice
を使用します。OPEN
(= 締め日)であればWait
→Success
に遷移するようにします。それ以外の場合(= 締め日でない)は、Pass
に遷移するようにします。
作成したステートマシンのAmazon States Language(以降ASL)は以下の通りです。
{
"Comment": "A description of my state machine",
"StartAt": "GetCalendarState",
"States": {
"GetCalendarState": {
"Type": "Task",
"Parameters": {
"CalendarNames": [
"arn:aws:ssm:us-east-1:<AWSアカウントID>:document/SettlementClosingDate"
]
},
"Resource": "arn:aws:states:::aws-sdk:ssm:getCalendarState",
"Next": "Choice"
},
"Choice": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.State",
"StringEquals": "OPEN",
"Next": "Wait"
}
],
"Default": "Pass"
},
"Wait": {
"Type": "Wait",
"Seconds": 5,
"Next": "Success"
},
"Success": {
"Type": "Succeed"
},
"Pass": {
"Type": "Pass",
"End": true
}
}
}
ステートマシンと一緒に作成されるIAMロールだと権限不足で、以下のように「GetCalendarState
APIの実行を許可する必要がある」と表示されます。
そのため、以下のようにGetCalendarState
APIの実行を許可するIAMポリシーを対象のIAMロールに追加します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ssm:GetCalendarState",
"Resource": "arn:aws:ssm:*:<AWSアカウントID>:document/*"
}
]
}
以上で締め日用カレンダーの動作確認で使うステートマシンの作成は完了です。
なお、今回は設定しませんが、締め日が毎月23日から25日の間のいずれかの日の10:00(JST)であれば、EventBridgeのCron式でcron(0 1 23-25 * ? *)
を設定し、作成したステートマシンを呼び出すように指定します。
ステートマシン内では締め日用カレンダーに登録されているイベントを参照し条件分岐するため、このように設定することで、23日から25日の中で締め日が変動しても、実際の締め日のみ処理を実行させることができます。
祝日用カレンダーの動作確認で使うステートマシン
続いて、祝日用カレンダーの動作確認で使うステートマシンを作成します。
締め日用カレンダーの動作確認で使うステートマシンと同様に、先頭のタスクでGetCalendarState
APIを呼び出し、休日用カレンダーを参照します。
Choice
の条件及び、条件分岐先は締め日用カレンダーの動作確認で使うステートマシンのものと同じです。
作成したステートマシンのASLは以下の通りです。
{
"Comment": "A description of my state machine",
"StartAt": "GetCalendarState",
"States": {
"GetCalendarState": {
"Type": "Task",
"Parameters": {
"CalendarNames": [
"arn:aws:ssm:us-east-1:<AWSアカウントID>:document/NationalHoliday"
]
},
"Resource": "arn:aws:states:::aws-sdk:ssm:getCalendarState",
"Next": "Choice"
},
"Choice": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.State",
"StringEquals": "OPEN",
"Next": "Wait"
}
],
"Default": "Pass"
},
"Wait": {
"Type": "Wait",
"Seconds": 5,
"Next": "Success"
},
"Success": {
"Type": "Succeed"
},
"Pass": {
"Type": "Pass",
"End": true
}
}
}
締め日用カレンダーのテスト
締め日用カレンダーのテストを行います。
作成した締め日用カレンダーの動作確認で使うステートマシンを実行すると、実行日が23日であり、カレンダーに登録した締め日の23日と一致しているため、OPEN
と判定されています。その結果、Choice
以降はWait
→Success
に遷移しています。
祝日用カレンダーのテスト
続いて、祝日用カレンダーのテストを行います。
作成した祝日用カレンダーの動作確認で使うステートマシンを実行すると、実行日が23日であり、カレンダーに登録した祝日の23日と一致しているため、CLOSED
と判定されています。その結果、Choice
以降はPass
に遷移しています。
複数のカレンダーがある場合も試してみた
ANDの場合
複数のカレンダーがある場合も試してみます。
まず、「締め日は基本実行するけど、休日だったら実行しない」のように2つのカレンダーをAND
で評価してみます。
ANDで評価する場合は、GetCalendarState
APIのCalendarNames
パラメーターに複数のSSM Change CalendarのARNを指定します。
その他の設定は変更ありません。
作成したステートマシンのASLは以下の通りです。
{
"Comment": "A description of my state machine",
"StartAt": "GetCalendarState",
"States": {
"GetCalendarState": {
"Type": "Task",
"Parameters": {
"CalendarNames": [
"arn:aws:ssm:us-east-1:<AWSアカウントID>:document/SettlementClosingDate",
"arn:aws:ssm:us-east-1:<AWSアカウントID>:document/NationalHoliday"
]
},
"Resource": "arn:aws:states:::aws-sdk:ssm:getCalendarState",
"Next": "Choice"
},
"Choice": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.State",
"StringEquals": "OPEN",
"Next": "Wait"
}
],
"Default": "Pass"
},
"Wait": {
"Type": "Wait",
"Seconds": 5,
"Next": "Success"
},
"Success": {
"Type": "Succeed"
},
"Pass": {
"Type": "Pass",
"End": true
}
}
}
カレンダー上では締め日かつ休日でもある23日に、作成したステートマシンを実行すると、意図した通りCLOSED
と判定されています。その結果、Choice
以降はPass
に遷移しています。
ORの場合
続いて、「締め日であれば休日であっても実行する」のように2つのカレンダーをOR
で評価してみます。
ORで評価する場合は、Pararell
でGetCalendarState
APIを並列で呼び出します。Pararell
の実行結果はJSONではなく配列になっているので、ResultPath
で整形してあげます。
後続のChoice
ではResultPath
で整形された各GetCalendarState
APIの結果をOR
で評価します。
作成したステートマシンのASLは以下の通りです。
{
"Comment": "A description of my state machine",
"StartAt": "Parallel",
"States": {
"Parallel": {
"Type": "Parallel",
"Next": "Choice",
"Branches": [
{
"StartAt": "GetCalendarState_SettlementClosingDate",
"States": {
"GetCalendarState_SettlementClosingDate": {
"Type": "Task",
"End": true,
"Parameters": {
"CalendarNames": [
"arn:aws:ssm:us-east-1:<AWSアカウントID>:document/SettlementClosingDate"
]
},
"Resource": "arn:aws:states:::aws-sdk:ssm:getCalendarState"
}
}
},
{
"StartAt": "GetCalendarState_NationalHoliday",
"States": {
"GetCalendarState_NationalHoliday": {
"Type": "Task",
"End": true,
"Parameters": {
"CalendarNames": [
"arn:aws:ssm:us-east-1:<AWSアカウントID>:document/NationalHoliday"
]
},
"Resource": "arn:aws:states:::aws-sdk:ssm:getCalendarState"
}
}
}
],
"ResultPath": "$.calendarState"
},
"Choice": {
"Type": "Choice",
"Choices": [
{
"Or": [
{
"Variable": "$.calendarState[0].State",
"StringEquals": "OPEN"
},
{
"Variable": "$.calendarState[1].State",
"StringEquals": "OPEN"
}
],
"Next": "Wait"
}
],
"Default": "Pass"
},
"Wait": {
"Type": "Wait",
"Seconds": 5,
"Next": "Success"
},
"Success": {
"Type": "Succeed"
},
"Pass": {
"Type": "Pass",
"End": true
}
}
}
カレンダー上では締め日かつ休日でもある23日に、作成したステートマシンを実行すると、意図した通りOPEN
と判定されています。その結果、Choice
以降はWait
→Success
に遷移しています。
またまたジョブ管理システムから抜け出すためのTipsを作りました
AWS Step FunctionsとAWS Systems Manager Change Calendarを連携してCron式では表現しづらいイレギュラーケースに対応してみました。
オンプレ環境でもCron式で表現し切れない定期実行は、実行するシェルスクリプト内でif文などを用いて対応していたと思いますが、イメージとしてはそれに近しいですね。
なお、作成したSSM Change Calendarはアカウント間でも共有できます。そのため、複数アカウントがある場合でもSSM Change Calendar管理用アカウント上のSSM Change Calendarを参照していれば、締め日が変わった場合なども対応の手間が少ないのではと考えます。
また、改めてAWS Step Functionsから直接APIを実行できるようになったのは神アップデートだと実感しました。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!