🚀

AWSのLambdaを1分よりも短い間隔で呼ぶ

2024/12/16に公開

目的

ユニークビジョン株式会社 Advent Calendar 2024のシリーズ2、12/5の記事です。

AWSのLambdaをバッチとして使いたいです。Eventbrige Schedulerでは最小1分単位で呼び出すことが可能ですが、30秒ごととか10秒ごとで設定できません。

ここではStep Functionを使ってこれを実現します。

説明

AWS Lambda

定期処理をするLambdaです。Rubyで書いています。
呼び出される度にカウントアップして返します。

require 'json'

def batch
  # 定期的に実行した処理
end

def lambda_handler(event:, context:)
  count = event['count'] || 0
  batch()
  { count: count + 1 }
end

Step Function

以下のようにStepFunctionを組みます。

StepFunctionでは1分以内で回したい数だけ呼び出します。
例えば20秒なら2回呼び出してそれぞれ20秒待つ。
例えば10秒なら5回呼び出してそれぞれ10秒待つ。

詳細は以下のようになります。ここでは20秒に1回呼ばれる想定をしています。

{
  "QueryLanguage": "JSONata",
  "Comment": "A description of my state machine",
  "StartAt": "Lambda Invoke",
  "States": {
    "Lambda Invoke": {
      "Type": "Task",
      "Resource": "arn:aws:states:::lambda:invoke",
      "Output": "{% $states.result.Payload %}",
      "Arguments": {
        "FunctionName": "arn:aws:lambda:us-east-1:xxxxxxxxxx:function:target_function:$LATEST",
        "Payload": "{% $states.input %}"
      },
      "Retry": [
        {
          "ErrorEquals": [
            "Lambda.ServiceException",
            "Lambda.AWSLambdaException",
            "Lambda.SdkClientException",
            "Lambda.TooManyRequestsException"
          ],
          "IntervalSeconds": 1,
          "MaxAttempts": 3,
          "BackoffRate": 2,
          "JitterStrategy": "FULL"
        }
      ],
      "Next": "Choice"
    },
    "Choice": {
      "Type": "Choice",
      "Choices": [
        {
          "Next": "成功",
          "Condition": "{% $states.input.count >= 2 %}"
        }
      ],
      "Default": "Wait"
    },
    "成功": {
      "Type": "Succeed"
    },
    "Wait": {
      "Type": "Wait",
      "Seconds": 20,
      "Next": "Lambda Invoke"
    }
  }
}

Eventbridge Scheduler

1分ごとに呼び出すcron式は以下の通りです。これ以上短くすることができません。
上記のStepFunctionを呼び出すように設定しておきます。

時間 曜日
*/1 * * * * ?

まとめ

Step Functionを利用することで1分よりも短いLambdaの呼び出しが可能になりました。
これをAWS Lambdaだけで実現しようとするとプログラム内でsleepすることになりコストが高くなります。StepFunctionは状態遷移で課金されますが20秒設定で8回動きます。
また月4000回の無料枠があり、それ以上はUSD 0.025/1,000 回の状態遷移で課金されます。
計算結果は以下の通りです。

(8 * 60 * 24 * 30 - 4000) / 1000 / 40 = 8.54

Lambdaの料金も含めてもおそらく10$もいかないと思います。
これがLambdaで起動し続けるとClaudeに聞いたら15分動かし続けると0.2$とのことで

0.2 * 4 * 24 * 30 = 576

10秒ごとでも15$だったのでだいぶお安いです。

Discussion