Amazon EventBridge SchedulerのCDK L2 Constructが利用可能になりました！

Amazon EventBridge SchedulerのCDK L2 ConstructがGAされました！🎉

https://aws.amazon.com/jp/about-aws/whats-new/2025/04/aws-cdk-construct-library-eventbridge-scheduler/

これまでCDKでEventBridge Schedulerを定義する場合、L1 Constructかアルファモジュール（実験的な機能を提供する安定版でないモジュール）を使う必要がありましたが、
今回のリリースによりL2 Constructを使った実装が可能になりました。

本記事では、実際にL2 Constructを使って定義し、動作確認した内容をまとめました。

## Amazon EventBridge Schedulerについて

詳しくは下記記事で分かりやすくまとめられていますが、Amazon EventBridge rulesと比較し、JSTでcron式を定義できたり、クォータ上限数でも大きなメリットがあります。

https://dev.classmethod.jp/articles/amazon-eventbridge-scheduler-new-way-to-launch-tasks/

## （準備）CDK アップデート
まずはローカル環境の準備を行います。

手元でCDKの最新インストールまたはアップデート
```shell
npm install -g cdk
```
バージョンを確認
```shell
cdk --version
2.1007.0 (build d3f6c3c)
```
aws-cdk-libのバージョンを最新の`2.187.0`に設定
```
"aws-cdk-lib": "2.187.0"
```

## 実装手順

ここからCDKのL2ConstructでEventBridge Schedulerを定義する方法を説明します。

### 1. （準備）ターゲットのリソースを作成
EventBridge Scheduler自体を設定する前に、スケジュール実行の対象となるリソースを先に作成します。今回はシンプルなStep Functionsを作成します。

何でも良いのですが、今回はStep Functionsを作成しておきます。

```ts
    const stepfunction = new stepfunctions.StateMachine(this, 'StateMachine', {
      definitionBody: stepfunctions.DefinitionBody.fromString('{"Comment": "A Hello World example of the Amazon States Language using a Pass state","StartAt": "HelloWorld","States": {"HelloWorld": {"Type": "Pass","Result": "Hello, World!","End": true}}}'),
    });
```

### 2. スケジュールとターゲットの定義
起動したいリソースを定義したので、次にEventBridge SchedulerをL2で定義してみようと思います。

下記のCDK公式ドキュメントを参考にしました。

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_scheduler-readme.html

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_scheduler.Schedule.html

schedulerの定義では下記が必須項目となっています。
- schedule
- target

scheduleは今回、cron形式で定義してみます。
EventBridge Schedulerの優れたポイントとして、JSTでcronルールを定義することができます。
L2Constructでは、`timeZone: cdk.TimeZone.ASIA_TOKYO`と記述することでJSTで定義が可能になります。

```ts
    const schedule = new scheduler.Schedule(this, 'Schedule', {
      schedule: scheduler.ScheduleExpression.cron({
        minute: '15',
        hour: '0',
        weekDay: 'SAT',
        timeZone: cdk.TimeZone.ASIA_TOKYO
      }),
      // 後ほどtargetをここに定義する
    });
```

次に、ターゲットを定義します。今回はStep Functionsをターゲットにするため、`aws-cdk-lib/aws-scheduler-targets`から`targets.StepFunctionsStartExecution`を使用します。また、ターゲットに渡すペイロードを`input`で指定できます。

```ts
    const target = new targets.StepFunctionsStartExecution(stepfunction, {
      input: scheduler.ScheduleTargetInput.fromObject({
        hoge: 'fuga',
      }),
    });
```

これでEventBridge Scheduler側に指定するtargetが完成しました。

:::note info
他のサービスをターゲットにする場合は、targetsから適切なクラスを選択します

- Lambdaの場合：targets.LambdaInvoke
- SNSの場合：targets.SnsPublish
:::

targetを指定し、非必須項目ですが分かりやすいように名称`scheduleName`を指定してみました。
```ts
    const schedule = new scheduler.Schedule(this, 'Schedule', {
      // スケジューラーの名前を指定
      scheduleName: 'my-first-scheduler-cdk',
      schedule: scheduler.ScheduleExpression.cron({
        minute: '15',
        hour: '0',
        weekDay: 'SAT',
        timeZone: cdk.TimeZone.ASIA_TOKYO
      }),
      // targetを指定
      target: target
    });
```

最終的なコードは下記のとおりです。

```lib/simple-app-cdk-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as scheduler from 'aws-cdk-lib/aws-scheduler'
import * as stepfunctions from 'aws-cdk-lib/aws-stepfunctions'
import * as targets from 'aws-cdk-lib/aws-scheduler-targets';

export class SimpleAppCdkStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const stepfunction = new stepfunctions.StateMachine(this, 'StateMachine', {
      definitionBody: stepfunctions.DefinitionBody.fromString('{"Comment": "A Hello World example of the Amazon States Language using a Pass state","StartAt": "HelloWorld","States": {"HelloWorld": {"Type": "Pass","Result": "Hello, World!","End": true}}}'),
    });

    const target = new targets.StepFunctionsStartExecution(stepfunction, {
      input: scheduler.ScheduleTargetInput.fromObject({
        hoge: 'fuga',
      }),
    });

    const schedule = new scheduler.Schedule(this, 'Schedule', {
      scheduleName: 'my-first-scheduler-cdk',
      schedule: scheduler.ScheduleExpression.cron({
        minute: '15',
        hour: '0',
        weekDay: 'SAT',
        timeZone: cdk.TimeZone.ASIA_TOKYO
      }),
      target: target
    });
  }
}

```

## 動作確認

cdk deployして実際にコンソール上で確認してみます。

![スクリーンショット 2025-04-05 0.14.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/415169/166aa20c-7663-4d8d-8bf4-f6f2b309f906.png)

ターゲットタイプがStep Functionsで作成できていますね。

![スクリーンショット 2025-04-05 0.15.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/415169/d4b3f422-c055-49b5-b1e0-ba9bf672c927.png)

また、cron式も設定できていることを確認できました。

![スクリーンショット 2025-04-05 0.16.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/415169/a07fdd3b-0048-4da2-8a95-1c39cdd8056a.png)

設定した時間になるとEventBridge SchedulerによってターゲットのStep Functionsも起動したことを確認できました。

## （補足）スケジュールグループとフレキシブルタイムウィンドウの設定

EventBridge Schedulerの特徴的なものとしてスケジュールグループとフレキシブルタイムウィンドウがあります。この2つの設定についても見ていきます。

下記ドキュメントを参考に作成してみました。

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_scheduler.ScheduleGroup.html

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_scheduler.TimeWindow.html

### スケジュールグループ
1. スケジュールグループを定義します。
2. スケジューラーのプロパティ`scheduleGrip`に、1で作成したスケジュールグループを設定します。

### フレキシブルタイムウィンドウ
スケジューラーのプロパティ`timeWindow`に、任意の時間で`TimeWindow.flexible()`を設定します。

最終的なコードは下記のようになります。（今回関連する部分のみ）!

```lib/simple-app-cdk-stack.ts
    // スケジュールグループの定義
    const scheduleGroup = new scheduler.ScheduleGroup(this, "ScheduleGroup", {
      scheduleGroupName: "SampleScheduleGroup",
  });

    const scheduleWithGroup = new scheduler.Schedule(this, 'ScheduleWithTarget', {
      scheduleName: 'my-second-scheduler-cdk',
      schedule: scheduler.ScheduleExpression.cron({
        minute: '15',
        hour: '0',
        weekDay: 'SAT',
        timeZone: cdk.TimeZone.ASIA_TOKYO
      }),
      target: target,
      // スケジュールグループを設定
      scheduleGroup: scheduleGroup,
      // フレキシブルタイムウィンドウの設定
      timeWindow: scheduler.TimeWindow.flexible(cdk.Duration.minutes(10)),
    })
```

### コンソール上で確認

スケジュールグループができていることを確認できました！

![スクリーンショット 2025-04-07 2.34.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/415169/34a4c8a6-2947-446d-b869-ca73ee59f8d2.png)

そして、作成したスケジュールグループにスケジューラーが紐づいていることも確認できました！
![スクリーンショット 2025-04-07 2.35.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/415169/1a84b495-a074-4d9d-8583-b30b95a7ed8e.png)

:::note info
#### フレキシブルタイムウィンドウの時間設定について
コンソール上では、
`5分/10分/15分/30分/1時間/2時間/4時間`から選択可能となっていますが
![スクリーンショット 2025-04-07 3.03.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/415169/7f2cca9e-2a36-43e8-95db-97910c847faf.png)
今回CDKのコードで
`cdk.Duration.minutes(7)`と、選択肢にない値で設定してみたところ、デプロイはでき、コンソール上にも、設定した7分で反映されていました。
:::

## まとめ

今回はEventBridge SchedulerのCDK L2 ConstructがGAされたので触って検証してみました！
前述の通りJSTでcron式を書けたり、クォータ上限にメリットがあるなど、とても使い勝手の良いサービスです。

今回のL2ConstructのGAにより、CDKでより簡潔に記述できるようになりました！
EventBridge Schedulerはとても使い勝手のいいサービスなので、ぜひ試してみてください！