AWS Step Functions State Machine の監視に必要な CloudWatch リソースを AWS CDK で簡単に作成できるメソッドが便利

2023.08.01

こんにちは、CX事業本部 Delivery部の若槻です。

下記で紹介されているように、AWS CDK にはリソースの監視に必要な CloudWatch のリソースを簡単に作成できる便利なメソッドが用意されています。

人の介入を必要としない完全な継続的デプロイメントという目標を達成するには高度な自動化が必要ですが、その自動化は膨大な量のモニタリングなしには不可能です。メトリクス、アラーム、ダッシュボードを作成して、デプロイされたリソースをあらゆる面から測定しましょう。また、CPU使用率やディスク容量などの単純な測定だけでなく、ビジネスメトリクスを記録し、それらの測定値を利用してロールバックなどの自動化を行いましょう。AWS CDKのL2 Constructの多くはdynamodb.TableクラスのmetricUserErrors()メソッドのように、メトリクスの作成に役立つ便利なメソッドを備えています。

今回は、AWS Step Functions State Machine の CloudWatch メトリクスおよびアラームを AWS CDK で簡単に作成する方法を確認してみます。

試してみた

CDK コード

CDK コードは次のようになります。

lib/cdk-sample-stack.ts

import { aws_stepfunctions, Stack, StackProps, Duration } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  public readonly myFileObjectKey: string;

  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    const myStateMachine = new aws_stepfunctions.StateMachine(
      this,
      'MyStateMachine',
      {
        definitionBody: aws_stepfunctions.DefinitionBody.fromChainable(
          new aws_stepfunctions.Pass(this, 'MyPass', {
            parameters: { key: aws_stepfunctions.JsonPath.stringAt('$.key') },
          })
        ),
      }
    );

    myStateMachine
      .metricFailed({
        period: Duration.minutes(1),
      })
      .createAlarm(this, 'FailedAlarm', {
        alarmName: `${myStateMachine.stateMachineName}-FailedAlarm`,
        threshold: 1,
        evaluationPeriods: 1,
      });

    myStateMachine.metricThrottled().createAlarm(this, 'ThrottledAlarm', {
      alarmName: `${myStateMachine.stateMachineName}-ThrottledAlarm`,
      threshold: 1,
      evaluationPeriods: 1,
    });

    myStateMachine.metricTimedOut().createAlarm(this, 'TimedOutAlarm', {
      alarmName: `${myStateMachine.stateMachineName}-TimedOutAlarm`,
      threshold: 1,
      evaluationPeriods: 1,
    });
  }
}
  • aws_stepfunctions.StateMachineConstruct から作成したインスタンスでmetricFailedmetricThrottledおよびmetricTimedOutメソッドを使って、それぞれの実行失敗、スロットルおよびタイムアウトのメトリクスを作成しています。
  • メトリクスを作成するインスタンスは、既定のピリオドは 5 分ですが、periodプロパティで変更できます。
  • createAlarmメソッドでメトリクスに対するアラームを作成しています。

デプロイ

スタックをデプロイします。

cdk deploy

デプロイされたスタックのリソース一覧を見ると、AWS::CloudWatch::Alarmリソースが3つ作成されていることが確認できます。

$ aws cloudformation list-stack-resources --stack-name CdkSampleStack
{
    "StackResourceSummaries": [
        {
            "LogicalResourceId": "CDKMetadata",
            "PhysicalResourceId": "e68b6900-f01c-11ed-8538-06bbc29e5367",
            "ResourceType": "AWS::CDK::Metadata",
            "LastUpdatedTimestamp": "2023-08-01T15:05:16.888Z",
            "ResourceStatus": "UPDATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "LogicalResourceId": "FailedAlarm85DAC8D4",
            "PhysicalResourceId": "MyStateMachine6C968CA5-VodcvzDcgH4C-FailedAlarm",
            "ResourceType": "AWS::CloudWatch::Alarm",
            "LastUpdatedTimestamp": "2023-08-01T15:05:51.598Z",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "LogicalResourceId": "MyStateMachine6C968CA5",
            "PhysicalResourceId": "arn:aws:states:ap-northeast-1:XXXXXXXXXXXX:stateMachine:MyStateMachine6C968CA5-VodcvzDcgH4C",
            "ResourceType": "AWS::StepFunctions::StateMachine",
            "LastUpdatedTimestamp": "2023-08-01T15:05:48.933Z",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "LogicalResourceId": "MyStateMachineRoleD59FFEBC",
            "PhysicalResourceId": "CdkSampleStack-MyStateMachineRoleD59FFEBC-2ZMFY24078M3",
            "ResourceType": "AWS::IAM::Role",
            "LastUpdatedTimestamp": "2023-08-01T15:05:45.269Z",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "LogicalResourceId": "ThrottledAlarm5718E5A0",
            "PhysicalResourceId": "MyStateMachine6C968CA5-VodcvzDcgH4C-ThrottledAlarm",
            "ResourceType": "AWS::CloudWatch::Alarm",
            "LastUpdatedTimestamp": "2023-08-01T15:05:51.646Z",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        },
        {
            "LogicalResourceId": "TimedOutAlarm29EC037C",
            "PhysicalResourceId": "MyStateMachine6C968CA5-VodcvzDcgH4C-TimedOutAlarm",
            "ResourceType": "AWS::CloudWatch::Alarm",
            "LastUpdatedTimestamp": "2023-08-01T15:05:51.952Z",
            "ResourceStatus": "CREATE_COMPLETE",
            "DriftInformation": {
                "StackResourceDriftStatus": "NOT_CHECKED"
            }
        }
    ]
}

作成された3つのアラームの詳細です。State Machine の各メトリクスに対するアラームがちゃんと作成されています。

$ aws cloudwatch describe-alarms
{
    "MetricAlarms": [
        {
            "AlarmName": "MyStateMachine6C968CA5-VodcvzDcgH4C-FailedAlarm",
            "AlarmArn": "arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXXX:alarm:MyStateMachine6C968CA5-VodcvzDcgH4C-FailedAlarm",
            "AlarmConfigurationUpdatedTimestamp": "2023-08-01T15:05:51.322Z",
            "ActionsEnabled": true,
            "OKActions": [],
            "AlarmActions": [],
            "InsufficientDataActions": [],
            "StateValue": "INSUFFICIENT_DATA",
            "StateReason": "Unchecked: Initial alarm creation",
            "StateUpdatedTimestamp": "2023-08-01T15:05:51.322Z",
            "MetricName": "ExecutionsFailed",
            "Namespace": "AWS/States",
            "Statistic": "Sum",
            "Dimensions": [
                {
                    "Name": "StateMachineArn",
                    "Value": "arn:aws:states:ap-northeast-1:XXXXXXXXXXXX:stateMachine:MyStateMachine6C968CA5-VodcvzDcgH4C"
                }
            ],
            "Period": 60,
            "EvaluationPeriods": 1,
            "Threshold": 1.0,
            "ComparisonOperator": "GreaterThanOrEqualToThreshold",
            "StateTransitionedTimestamp": "2023-08-01T15:05:51.322Z"
        },
        {
            "AlarmName": "MyStateMachine6C968CA5-VodcvzDcgH4C-ThrottledAlarm",
            "AlarmArn": "arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXXX:alarm:MyStateMachine6C968CA5-VodcvzDcgH4C-ThrottledAlarm",
            "AlarmConfigurationUpdatedTimestamp": "2023-08-01T15:05:51.320Z",
            "ActionsEnabled": true,
            "OKActions": [],
            "AlarmActions": [],
            "InsufficientDataActions": [],
            "StateValue": "INSUFFICIENT_DATA",
            "StateReason": "Unchecked: Initial alarm creation",
            "StateUpdatedTimestamp": "2023-08-01T15:05:51.320Z",
            "MetricName": "ExecutionThrottled",
            "Namespace": "AWS/States",
            "Statistic": "Sum",
            "Dimensions": [
                {
                    "Name": "StateMachineArn",
                    "Value": "arn:aws:states:ap-northeast-1:XXXXXXXXXXXX:stateMachine:MyStateMachine6C968CA5-VodcvzDcgH4C"
                }
            ],
            "Period": 300,
            "EvaluationPeriods": 1,
            "Threshold": 1.0,
            "ComparisonOperator": "GreaterThanOrEqualToThreshold",
            "StateTransitionedTimestamp": "2023-08-01T15:05:51.320Z"
        },
        {
            "AlarmName": "MyStateMachine6C968CA5-VodcvzDcgH4C-TimedOutAlarm",
            "AlarmArn": "arn:aws:cloudwatch:ap-northeast-1:XXXXXXXXXXXX:alarm:MyStateMachine6C968CA5-VodcvzDcgH4C-TimedOutAlarm",
            "AlarmConfigurationUpdatedTimestamp": "2023-08-01T15:05:51.582Z",
            "ActionsEnabled": true,
            "OKActions": [],
            "AlarmActions": [],
            "InsufficientDataActions": [],
            "StateValue": "INSUFFICIENT_DATA",
            "StateReason": "Unchecked: Initial alarm creation",
            "StateUpdatedTimestamp": "2023-08-01T15:05:51.582Z",
            "MetricName": "ExecutionsTimedOut",
            "Namespace": "AWS/States",
            "Statistic": "Sum",
            "Dimensions": [
                {
                    "Name": "StateMachineArn",
                    "Value": "arn:aws:states:ap-northeast-1:XXXXXXXXXXXX:stateMachine:MyStateMachine6C968CA5-VodcvzDcgH4C"
                }
            ],
            "Period": 300,
            "EvaluationPeriods": 1,
            "Threshold": 1.0,
            "ComparisonOperator": "GreaterThanOrEqualToThreshold",
            "StateTransitionedTimestamp": "2023-08-01T15:05:51.582Z"
        }
    ],
    "CompositeAlarms": []
}

動作確認

まずは、State Machine を成功させるように実行させます。

$ aws stepfunctions start-execution \
  --state-machine-arn ${StateMachineArn} \
  --input "{\"key\" : \"value\"}"

アラームが OK 状態となりました。

$ aws cloudwatch describe-alarms \
  --query "MetricAlarms[?AlarmName=='${failedAlarmName}'].StateValue" \
  --output text
OK

続いて、State Machine を失敗させるように実行させます。

$ aws stepfunctions start-execution \
  --state-machine-arn ${StateMachineArn} \
  --input "{\"invalid_key\" : \"value\"}"

アラームが ALARM 状態となりました。

$ aws cloudwatch describe-alarms \
  --query "MetricAlarms[?AlarmName=='${failedAlarmName}'].StateValue" \
  --output text
ALARM

AWS リソースの監視に必要な CloudWatch のリソースを簡単に作成することができました。

CDK のドキュメントを読む

ドキュメントを読むと、メトリクスやアラームの設定方法が他にも紹介されています。

前述のメソッドチェーンの書き方ではなく、次のように記述してアラームを作成することも可能です。

declare const stateMachine: sfn.StateMachine;
new cloudwatch.Alarm(this, 'StateMachineAlarm', {
  metric: stateMachine.metricFailed(),
  threshold: 1,
  evaluationPeriods: 1,
});

Step Functions の Task オブジェクトに同様にメトリクスを設定することもできます。

declare const task: sfn.Task;
new cloudwatch.Alarm(this, 'TaskAlarm', {
  metric: task.metricFailed(),
  threshold: 1,
  evaluationPeriods: 1,
});

次のように AWS アカウント内のすべての State Machine のメトリクスを一括で監視するアラームを作成することもできます。

new cloudwatch.Alarm(this, 'ThrottledAlarm', {
  metric: sfn.StateTransitionMetric.metricThrottledEvents(),
  threshold: 10,
  evaluationPeriods: 2,
});

DynamoDB テーブルの場合

今回は Step Functions の State Machine を例に紹介しましたが、DynamoDB テーブルのメトリクスやアラームも同様に作成できます。次の記事で紹介されています。

おわりに

AWS Step Functions State Machine の CloudWatch メトリクスおよびアラームを AWS CDK で簡単に作成する方法を確認してみました。

以前まで頑張って Namespace やら Dimension やらを直書きして設定していたのですが、そのようなことをしなくても監視や通知に必要なリソースを簡単に作成できることが分かりました。便利ですね。今後使っていきたいです。

参考

以上