AR ホームベーカリー

オイラのアウトプット用ホームベーカリー!

CloudWatch Events (EventBridge) で月末日をトリガーにするスケジュールは日付に L を指定する

タイトルで終了してしまったシリーズ。

月末に処理を実行する

BtoB・BtoC 問わずで、月末日・月末締め毎月1日、みたいなタイミングでバッチ処理したいというシチュエーションは結構発生すると思います。

で、今回は開発の人から提供してもらった以下のコマンドを Terraform で流し込んだのでした。

毎月 27 日〜 31 日の範囲で、 (シェルスクリプトの test 構文で) date コマンドの日付部分が 01 つまり月初だったら真となり && 以降の runner が実行されるという具合。

# UTC で毎月 27 日〜 31 日 21 時、すなわち JST で 1 日 6 時にスケジュール
resource "aws_cloudwatch_event_rule" "Seikyusho" {
  name                = "Seikyusho"
  schedule_expression = "cron(0 21 27-31 * ? *)"
}

# スケジュールから起動するタスク
resource "aws_cloudwatch_event_target" "Seikyusho" {

...

  input     = jsonencode({
    containerOverrides = [
        {
          name = "scheduled_task",
          command = [ "[ `date -d tomorrow '+%d'` == '01' ] && bundle exec bin/rails runner 'Seikyusho.perform_later'" ]
        }
    ]
  })

...

}

これ多分 /bin/bash なら動くと思うんだけど、 /bin/sh だと [ "`date -d tomorrow '+%d'` == '01'" ] などとしないと unexpected operator になるはず (なった)。

で、前述の通り Terraform から流し込んでるので、 command 全体を括るために " を利用しており、「どうすりゃいいのか」という感じでシュッと解決できなかった。

スケジュールを修正する

どうすりゃいいのか、となっていたのだけど、 && で判断する処理を入れなくても月末が特定できりゃシンプルに表現できるんじゃねえの? と思って調べたら、似たような悩みを持った先人が居たのだった。

michimani.net

ナルホド L 、という感じだった。 AWS のスケジュール指定 ? が必要なアレといい独特すぎるけど、確かに既存の cron のスケジュール足りない所あるもんな。

resource "aws_cloudwatch_event_rule" "Seikyusho" {
  name                = "Seikyusho"
  schedule_expression = "cron(0 21 L * ? *)"
}

# スケジュールから起動するタスク
resource "aws_cloudwatch_event_target" "Seikyusho" {

...

  input     = jsonencode({
    containerOverrides = [
        {
          name = "scheduled_task",
          command = [ "bundle exec bin/rails runner 'Seikyusho.perform_later'" ]
        }
    ]
  })

...

}

マネジメントコンソールからスケジュールを確認している仕草

これでめでたく期待する動作に修正できたのだった。 いやーよかったよかった。