ちょっと話題の記事

定期実行するLambdaが「起動しなかったこと」を検知するCloudWatch Alarmを作る

「1時間に1回起動するLambda」や「1日に1回起動するLambda」といった定期実行するLambdaが「起動しなかったこと」を検知するCloudWatch Alarmを作ってみました。
2021.07.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Lambdaを定期実行する仕組みをよく作ります。

  • 1時間に1回起動する
  • 1日に1回起動する

これらのLambdaが「起動しなかった場合」に通知が欲しくなったので、CloudWatch Alarmを作ってみました。

実際にLambdaが起動しない事象に遭遇したことは無いですが、このAlarmがあると、「ちゃんと起動しているよね?」というモヤモヤが解消されます。万が一に気づける保険ですね。

おすすめの方

  • 定期実行するLambdaが「起動しなかった場合」のCloudWatch Alarmを作りたい方

定期実行するLambdaとCloudWatch Alarmを作成する

sam init

sam init \
    --runtime python3.8 \
    --name Lambda-No-Start-Alarm-Sample \
    --app-template hello-world \
    --package-type Zip

SAMテンプレート

CloudWatch Alarmは、Period(期間) * EvaluationPeriods(評価期間)を1時間または1日にしています。

  • 1時間に1回起動するLambda
    • Period(期間): 5分
    • EvaluationPeriods(評価期間): 12
    • Statistic(統計): Sum
  • 1日に1回起動するLambda
    • Period(期間): 5分
    • EvaluationPeriods(評価期間): 288
    • Statistic(統計): Sum

これにより、次の条件を満たすとアラーム状態になります。

  • 「12データポイント(12個*5分=60分) の Invocationsの合計」が1より小さい
  • 「288データポイント(288個*5分=24時間) の Invocationsの合計」が1より小さい

Lambdaが起動しないことを確認したいので、「Invocationsメトリクスが無ければNG」です。 期間を5分から1分にすることも可能ですが、「Invocationsメトリクス」の到着が少し遅れるとすぐにアラーム状態になるため、余裕を見て5分にしています。 期間を60分にした場合も、「Invocationsメトリクス」の到着具合によってアラーム状態にならない可能性があります。

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Lambda-No-Start-Alarm-Sample

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.8
      Timeout: 5
      Events:
        HelloWorld:
          Type: Schedule
          Properties:
            Schedule: cron(0 */1 * * ? *) # 毎時0分に実行
            Enabled: true

  HelloWorldFunctionLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}

  HelloWorldFunction2:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.8
      Timeout: 5
      Events:
        HelloWorld:
          Type: Schedule
          Properties:
            Schedule: cron(0 3 * * ? *) # 毎日12時に実行(JST)
            Enabled: true

  HelloWorldFunctionLogGroup2:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lambda/${HelloWorldFunction2}

  HelloWorldFunctionInvocationsAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      Namespace: AWS/Lambda
      Dimensions:
        - Name: FunctionName
          Value: !Ref HelloWorldFunction
      MetricName: Invocations
      ComparisonOperator: LessThanThreshold
      Period: 300
      EvaluationPeriods: 12
      Statistic: Sum
      Threshold: 1
      TreatMissingData: breaching
      # AlarmActions:
      #   - !Ref any-sns-topic
      # OKActions:
      #   - !Ref any-sns-topic

  HelloWorldFunction2InvocationsAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      Namespace: AWS/Lambda
      Dimensions:
        - Name: FunctionName
          Value: !Ref HelloWorldFunction2
      MetricName: Invocations
      ComparisonOperator: LessThanThreshold
      Period: 300
      EvaluationPeriods: 288
      Statistic: Sum
      Threshold: 1
      TreatMissingData: breaching
      # AlarmActions:
      #   - !Ref any-sns-topic
      # OKActions:
      #   - !Ref any-sns-topic

Lambdaコード

Lambdaが起動すればOKなので、何もしません。

app.py

def lambda_handler(event, context):
    pass

デプロイ

デプロイします。

sam build

sam package \
    --output-template-file packaged.yaml \
    --s3-bucket cm-fujii.genki-deploy

sam deploy \
    --template-file packaged.yaml \
    --stack-name Lambda-No-Start-Alarm-Sample-Stack \
    --s3-bucket cm-fujii.genki-deploy \
    --capabilities CAPABILITY_NAMED_IAM \
    --no-fail-on-empty-changeset

デプロイ直後は過去に動いたLambdaが無いので、アラーム発生状態になります。落ち着くまでしばらく待ちます。

1時間に1回起動するLambdaのアラームを確認する

アラーム未発生を確認する

1時間ごとにLambdaが起動しているため、アラーム状態ではありません。

1時間毎にLambdaが実行されている

1時間毎にLambdaが実行されている

Lambdaの定期実行を無効化して、アラーム発生を確認する

CloudWatch Events(EventBridge)のルールを無効化します。 Lambdaが実行するはずの時刻をすぎると、アラーム状態になりました。

Lambdaが起動しないので、アラーム状態になった

Lambdaの定期実行を有効にして、アラーム解除を確認する

CloudWatch CloudWatch Events(EventBridge)のルールを有効に戻し、Lambdaが動くまで待つと、アラーム状態が解除されました。

Lambdaが起動したので、アラーム状態が解除された

履歴の様子は下記です。

アラームの履歴

1日に1回起動するLambdaのアラームを確認する

アラーム未発生を確認する

1日ごとにLambdaが起動しているため、アラーム状態ではありません。

1日毎にLambdaが実行されている

1日毎にLambdaが実行されている

Lambdaの定期実行を無効化して、アラーム発生を確認する

CloudWatch Events(EventBridge)のルールを無効化します。 Lambdaが実行するはずの時刻をすぎると、アラーム状態になりました。

Lambdaが起動しないので、アラーム状態になった

Lambdaの定期実行を有効にして、アラーム解除を確認する

CloudWatch Events(EventBridge)のルールを有効に戻し、Lambdaが動くまで待つと、アラーム状態が解除されました。

Lambdaが起動したので、アラーム状態が解除された

履歴の様子は下記です。

アラームの履歴

さいごに

定期実行するLambdaが「起動しない場合」のアラームを作ってみました。「ちゃんと起動しているよね?」というモヤモヤが解消されるので、意外と役に立つと思います。

参考