EventBridge Schedulerをプログラムから作成する

EventBridge Schedulerをプログラムから作成する

目次

はじめに

あるアプリケーションでLambdaをEventBridge Schedulerで5分おきに実行させるような構成を取っていました。

これをアプリケーションからEventBridge Scheduler APIを呼び出してスケジュールを動的に作成するようにできないかと考えました。

そこでまずはコンソールアプリで実際にSchedulerが作成できるかを検証したいと思います。

 

前提条件

今回実際にSchedulerで動かすのは既に作成済みのLambdaになります。

この時点で、IAMの用意も完了しているところからスタートになります。

コンソールアプリを作成

ターミナル上で下記を実行し、コンソールアプリを作成します。

> dotnet new console -n AWSSchedulerTest

コンソールアプリが作成できたら一応、実行します。

> dotnet run
Hello, World!

問題なさそうです。

初期のコードは消して検証していきます。

 

APIを呼び出す

パッケージをインストール

まずは必要なパッケージをインストールします。

> dotnet add package AWSSDK.Scheduler
> dotnet add package AWSSDK.SSOOIDC
> dotnet add package AWSSDK.SSO

インストールできたらProgram.csで読み込みましょう。

using Amazon.Scheduler;
using Amazon.Scheduler.Model;
using Amazon.Runtime;
using Amazon.Runtime.CredentialManagement;

SSOプロファイルを使って対象アカウントにログインします。

var chain = new CredentialProfileStoreChain();
if (!chain.TryGetAWSCredentials("your-profile-name", out var credentials) || credentials is null)
{
    Console.WriteLine("Error: AWS profile 'your-profile-name' could not be loaded. Run 'aws sso login --profile your-profile-name' first.");
    return;
}

クライアントにSSOで取得したクレデンシャルを渡し、東京リージョンを指定します。

var client = new AmazonSchedulerClient(credentials, Amazon.RegionEndpoint.APNortheast1);

スケジューラ名とスケジューラの作成時間を定義します。

スケジューラ名は一意である必要があるので、いくつも作成する場合は後ろにGUIDなどをつけてください。

ScheduleExpression に渡す時刻はJSTとして解釈されます。 しかし DateTime.UtcNow はUTC時刻を返すため、そのまま渡すと 実際より9時間前の時刻として扱われ、スケジューラが即時実行されてしまいます。
そのため AddHours(9) でUTC→JST変換を行い、JSTの5分後を指定しています。

// 現在時刻の5分後にスケジュール作成(JST基準)
var startTime = DateTimeOffset.UtcNow.AddHours(9).AddMinutes(5);
// スケジュール名
var scheduleName = "scheduler-test";

try catch内にAPIを呼び出すコードを書きます。

try{
    var response = await client.CreateScheduleAsync(new CreateScheduleRequest
    {
        // スケジュールの名前(同名は作成不可のためユニークな値を指定)
        Name = scheduleName,
        // 実行時刻の指定 at(...)形式で1回だけ実行するワンタイムスケジュールを作成
        // yyyy-MM-ddTHH:mm:ss形式のUTC時刻を渡す
        ScheduleExpression = $"at({startTime:yyyy-MM-ddTHH:mm:ss})",
        // ScheduleExpressionで指定した時刻のタイムゾーン
        // Asia/Tokyoを指定することでJSTとして解釈される
        ScheduleExpressionTimezone = "Asia/Tokyo",
        // スケジュール実行後の動作 DELETEを指定することで実行後に自動削除される
        // ワンタイムスケジュールは実行後不要になるため削除しておくと管理が楽になる        
        ActionAfterCompletion = ActionAfterCompletion.DELETE,
        // 実行時間のずれをどこまで許容するかの設定
        // OFFにすることで指定時刻ちょうどに実行される(柔軟な時間枠を使わない)
        FlexibleTimeWindow = new FlexibleTimeWindow
        {
            Mode = FlexibleTimeWindowMode.OFF
        },
        // スケジュール実行時に呼び出すターゲットの設定
        Target = new Target
        {
            // 呼び出すLambda関数のARN
            Arn = "arn:aws:lambda:ap-northeast-1:12345678912:function:your-lambda-name",
            // EventBridge SchedulerがLambdaを呼び出す際に使用するIAMロールのARN
            RoleArn = "arn:aws:iam::12345678912:role/your-scheduler-role",
            // Lambda関数に渡すペイロード(JSON形式)
            // Lambda側でeventとして受け取ることができる
            Input = "{\"key\": \"value\"}"
        }
    });
    Console.WriteLine($"作成成功: {response.ScheduleArn}");
}catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}

 

最後に下記が全体のソースコードです。

using Amazon.Scheduler;
using Amazon.Scheduler.Model;
using Amazon.Runtime;
using Amazon.Runtime.CredentialManagement;

var chain = new CredentialProfileStoreChain();
if (!chain.TryGetAWSCredentials("your-profile-name", out var credentials) || credentials is null)
{
    Console.WriteLine("Error: AWS profile 'your-profile-name' could not be loaded. Run 'aws sso login --profile your-profile-name' first.");
    return;
}

var client = new AmazonSchedulerClient(credentials, Amazon.RegionEndpoint.APNortheast1);

// 検証用: 現在時刻の5分後にスケジュール作成(JST基準)
var startTime = DateTimeOffset.UtcNow.AddHours(9).AddMinutes(5);
// var scheduleName = $"test-grant-{Guid.NewGuid():N}";
var scheduleName = "scheduler-test";

try
{
    var response = await client.CreateScheduleAsync(new CreateScheduleRequest
    {
        // スケジュールの名前(同名は作成不可のためユニークな値を指定)
        Name = scheduleName,
        // 実行時刻の指定 at(...)形式で1回だけ実行するワンタイムスケジュールを作成
        // yyyy-MM-ddTHH:mm:ss形式のUTC時刻を渡す
        ScheduleExpression = $"at({startTime:yyyy-MM-ddTHH:mm:ss})",
        // ScheduleExpressionで指定した時刻のタイムゾーン
        // Asia/Tokyoを指定することでJSTとして解釈される
        ScheduleExpressionTimezone = "Asia/Tokyo",
        // スケジュール実行後の動作 DELETEを指定することで実行後に自動削除される
        // ワンタイムスケジュールは実行後不要になるため削除しておくと管理が楽になる        
        ActionAfterCompletion = ActionAfterCompletion.DELETE,
        // 実行時間のずれをどこまで許容するかの設定
        // OFFにすることで指定時刻ちょうどに実行される(柔軟な時間枠を使わない)
        FlexibleTimeWindow = new FlexibleTimeWindow
        {
            Mode = FlexibleTimeWindowMode.OFF
        },
        // スケジュール実行時に呼び出すターゲットの設定
        Target = new Target
        {
            // 呼び出すLambda関数のARN
            Arn = "arn:aws:lambda:ap-northeast-1:12345678912:function:your-lambda-name",
            // EventBridge SchedulerがLambdaを呼び出す際に使用するIAMロールのARN
            RoleArn = "arn:aws:iam::12345678912:role/your-scheduler-role",
            // Lambda関数に渡すペイロード(JSON形式)
            // Lambda側でeventとして受け取ることができる
            Input = "{\"key\": \"value\"}"
        }
    });
    Console.WriteLine($"作成成功: {response.ScheduleArn}");
}
catch (Exception ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}

プログラムを実行する

aws sso login --profile your-profile-name 

プログラムを実行します。

> dotnet run
作成成功: arn:aws:scheduler:ap-northeast-1:12345678912:schedule/default/scheduler-test

実行が成功したので、マネジメントコンソールでSchedulerが作成されたか確認します。

無事に作成できていました。

実行時間も作成から5分後になってます。

まとめ

パッケージをインストールして、APIにパラメータを渡すだけで簡単にスケジューラを作成することができました。

この記事が皆さまのお役に立てれば嬉しいです。