Amazon EventBridge Schedulerは、cron式やrate式で指定した時刻にAWSのAPIを直接呼び出すフルマネージドのスケジューラです。AWSは従来のスケジュールされたルールを「EventBridgeのレガシー機能」と明記し、定時起動にはSchedulerの利用を推奨しています。この記事では、CreateScheduleを中心とする12のAPI操作、cron式とタイムゾーンの評価規則、即時実行のAPIが無い前提での手動実行、実行ロールと失敗の検知(DLQ・CloudWatchメトリクス)、CloudFormation・Terraform・CDKでの定義、東京リージョンのクォータと料金を、AWS公式ドキュメントの記載値に沿って整理します。
まとめ
- Scheduler APIの操作は12個だけです。スケジュール5操作、スケジュールグループ4操作、タグ3操作で構成され、スケジュールを即時実行する操作はありません。
- 手動実行は、1〜2分後を指す at 式の単発スケジュールを
ActionAfterCompletion=DELETE付きで作るのが正攻法です。ターゲットのAPIを直接叩く方法では、実行ロールの権限もInputの受け渡しも検証できません。 - cron式は6フィールド(分 時 日 月 曜日 年)です。日フィールドと曜日フィールドの両方に
*は指定できず、片方は?にします。 - 実行ロールの信頼ポリシーで
aws:SourceArnを絞るときは、スケジュールではなくスケジュールグループのARNを指定します。 - DLQに使えるのはSQSの標準キューだけで、FIFOキューは指定できません。CloudWatchメトリクスのディメンションはスケジュールグループ単位なので、監視を分けたい単位でグループを切ります。
- 東京リージョン(ap-northeast-1)の料金は月1,400万回の呼び出し(全リージョン合算)まで無料、超過分は100万回あたり1.25 USDです。1.00 USDはバージニア北部(us-east-1)の単価です。
EventBridge SchedulerとEventBridgeルールの使い分け
EventBridge Schedulerは、EventBridge本体(イベントバスとルール)とは別のAPIエンドポイントとサービス名前空間を持つコンポーネントです。エンドポイントは scheduler、リソースARNは arn:aws:scheduler:... で、IAMのアクションも scheduler:CreateSchedule のように分かれています。EventBridge本体の役割分担についてはAmazon EventBridgeとは?仕組み・料金とCLI・Pythonでの実装手順、新Custom Event Busとの違いを解説【2026年版】を参照してください。
上限とターゲット数の構造差
| 項目 | EventBridge Scheduler | EventBridgeルール(スケジュール) |
|---|---|---|
| 最大数 | 10,000,000(リージョンごと) | 300(イベントバスごと) |
| 上限の引き上げ | 可(数十億まで) | 可 |
| 1件あたりのターゲット数 | 1 | 5(引き上げ不可) |
| 呼び出しスロットル(東京) | 1,000 TPS | 2,250 TPS |
| タイムゾーン指定 | 可(IANA) | UTC固定 |
| 実行時刻の分散 | フレックスタイムウィンドウ | なし |
| 単発実行 | at式で可 | 不可 |
ルール数の上限300には例外があり、af-south-1 と eu-south-1 は100です。東京リージョンの呼び出しスロットルはEventBridgeルール側(2,250 TPS)のほうが高い点も見落としがちですが、Scheduler側の1,000 TPSは引き上げ申請の対象で、AWSは数万TPSまで調整可能と明記しています。
選択の判断基準
時刻起動が目的なら、新規構築ではSchedulerを選びます。AWS公式のスケジュールされたルールの解説ページには「Scheduled rules are a legacy feature of EventBridge.」という注記があり、「We recommend that you use Scheduler to invoke targets on a schedule.」と推奨先まで書かれているためです。ルール数300という上限も、テナントごとやユーザーごとにスケジュールを発行する設計では早期に枯渇します。CloudWatch Events時代に作ったスケジュールされたルールを棚卸しして移す際の確認点は、CloudWatch EventsとEventBridgeの違い:同じAPIで動く範囲と移行時の確認手順にまとめています。
EventBridgeルールを選ぶ理由には、API destinationsへの直接配信などがあります。以下の2つも代表的な判断材料です。1つは、1回の起動で最大5つのターゲットへ同時に配信したい場合。もう1つは、時刻起動ではなくS3やCodePipelineなどが発行するイベントのパターンマッチングが目的の場合です。既存ルールの移行は、ターゲットの対応範囲と移行コストを確認して判断します。件数上限が課題になる構成では、上限に達する前にSchedulerへの移行を計画します。
Step Functionsとの役割分担
AWS Step Functionsは競合ではなく接続先です。Schedulerが担うのは「いつ起動するか」だけで、起動後の分岐・リトライ・待機・並列実行はステートマシンに任せ、Schedulerのテンプレートターゲット StartExecution からそのARNを呼びます。複数ステップの処理をスケジュールの時刻でつなぐ設計は避けてください。前段の処理が遅延しても後段は予定時刻に走るため、依存関係が壊れます。ステートマシンの構成はAWS Step Functionsとは?ステートマシンの仕組み・料金と2種のワークフロー・採用判断を実装者目線で解説で確認できます。
スケジュール式の3タイプとタイムゾーン・サマータイムの評価規則
すべてのスケジュールタイプは60秒精度で動作します。1:00に設定した場合、フレックスタイムウィンドウを使わなければ 1:00:00 から 1:00:59 の間にターゲットのAPIが呼ばれます。秒単位の起動保証はありません。式の仕様は公式のSchedule typesが一次情報です。
rate式による一定間隔の起動
構文は rate(値 単位) で、値は正の整数、単位は minute/minutes/hour/hours/day/days が有効です。StartDate を指定しない場合、スケジュールを作成して有効化した直後から起動が始まります。
サマータイムを採用する地域でも、rate(1 days) は「時計上の翌日同時刻」ではなく前回起動から24時間後として評価されます。日が23時間や25時間になる日をまたぐと、起動時刻が1時間ずれます。日次バッチで時刻を固定したいならcron式を使います。
cron式の6フィールドとワイルドカード
構文は cron(分 時 日 月 曜日 年) の6フィールドです。UNIXのcronは5フィールドなので、年フィールドを忘れると ValidationException になります。
| フィールド | 値 | ワイルドカード |
|---|---|---|
| 分 | 0-59 | , – * / |
| 時 | 0-23 | , – * / |
| 日 | 1-31 | , – * ? / L W |
| 月 | 1-12 または JAN-DEC | , – * / |
| 曜日 | 1-7 または SUN-SAT | , – * ? L # |
| 年 | 1970-2199 | , – * / |
日フィールドと曜日フィールドの両方に * を指定することはできません。片方に * を使うなら、もう片方は「任意」を意味する ? にします。L は月末または週末、W は指定日に最も近い平日を表し、曜日フィールドの # は月内の何番目かを指定します。たとえば 3#2 は第2火曜日です。# を使うときは曜日フィールドに式を1つしか書けず、3#1,6#3 は無効です。
# 毎日9時(指定タイムゾーン)
cron(0 9 * * ? *)
# 毎月最終金曜日の10:15、2026年から2027年まで
cron(15 10 ? * 6L 2026-2027)
# 平日の毎時0分と30分
cron(0,30 * ? * MON-FRI *)
at式による単発起動と実行後の後始末
構文は at(yyyy-mm-ddThh:mm:ss) です。単発スケジュールでは StartDate と EndDate は無視されます。
運用上の落とし穴は、実行済みの単発スケジュールも、削除するまでリージョンのスケジュール数クォータを消費し続けることです。AWSはクォータ表の注記で「We recommend configuring your schedules to automatically delete after completion using the ActionAfterCompletion feature.」と自動削除を推奨しており、値は NONE(既定)か DELETE の2つです。単発スケジュールを動的に発行する設計では、作成時に DELETE を必ず指定してください。
cron式やrate式の定期スケジュールに DELETE を付ける場合は条件が1つ増えます。公式ドキュメントは「If you configure a schedule with automatic deletion but do not specify a value for EndDate, EventBridge Scheduler does not automatically delete the schedule.」と述べており、EndDate を指定しない定期スケジュールは DELETE を設定しても削除されません。削除の起点は EndDate に最も近い最終起動だからです。
タイムゾーンとサマータイムの挙動
タイムゾーンはIANAのTime Zone Databaseに基づき ScheduleExpressionTimezone(CLIでは --schedule-expression-timezone)で Asia/Tokyo のように指定します。サマータイムは自動調整され、公式の規則は「春の時刻前進で存在しない時刻に当たる回はスキップ」「秋の時刻巻き戻しで2回訪れる時刻は1回だけ実行」の2つです。America/Los_Angeles(2:00に時刻が切り替わる)で当てはめると次のようになります。
- 春の時刻前進(2:00が3:00に進む日):
cron(30 2 * * ? *)の2:30は存在しないため、その日の起動はスキップされ、翌日から通常どおり再開します。 - 秋の時刻巻き戻し(2:00が1:00に戻る日):
cron(30 1 * * ? *)の1:30は2回訪れますが、実行は1回だけです。
公式ドキュメントの例は秋の巻き戻しを「2:59から2:00」として2:30の挙動を説明していますが、ロサンゼルスで重複するのは1時台なので、2:30のスケジュールは秋の切り替えの影響を受けません。
Asia/Tokyo やUTC指定のスケジュールではこの調整は発生しません。
フレックスタイムウィンドウの設定値と使いどころ
FlexibleTimeWindow はCreateScheduleの必須パラメータです。使わない場合も {"Mode":"OFF"} を明示する必要があります。
| プロパティ | 必須 | 値 |
|---|---|---|
| Mode | 必須 | OFF / FLEXIBLE |
| MaximumWindowInMinutes | FLEXIBLE時 | 1〜1440(分) |
FLEXIBLE にすると、指定時刻を起点とする最大1440分(24時間)のウィンドウ内でEventBridge Schedulerが起動タイミングを決めます。数千件のスケジュールを同じ時刻に集中させた場合の詰まりどころは、ターゲット側(Lambdaの同時実行数、RDSの接続数、外部APIのレート制限)です。ウィンドウを15分から60分程度取れば、その山を平坦化できます。
逆に、締め処理や外部システムとの時刻合わせなど、実行時刻そのものが要件になっている処理にFLEXIBLEを使ってはいけません。起動時刻はウィンドウ内のどこになるか制御できず、ログ上の実行時刻から「遅延」と「仕様どおり」を区別できなくなります。この用途では OFF を選び、スケジュール自体の時刻を数分ずつずらして分散させます。
ターゲット指定の2方式と実行ロール
1つのスケジュールに指定できるターゲットは1つで、テンプレートターゲットかユニバーサルターゲットのいずれかを選びます。どちらの方式でも、ターゲットのAPIを呼ぶ権限を持つ実行ロール(RoleArn)が必須です。
実行ロールの信頼ポリシーとiam:PassRole
実行ロールは scheduler.amazonaws.com が引き受けるロールです。混乱した代理問題の防止のページは、信頼ポリシーに aws:SourceAccount と aws:SourceArn の条件を付けることを推奨しています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "scheduler.amazonaws.com" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "123456789012",
"aws:SourceArn": "arn:aws:scheduler:ap-northeast-1:123456789012:schedule-group/default"
}
}
}
]
}
ここで間違えやすいのが aws:SourceArn の値です。公式ページは「Do not scope the aws:SourceArn statement to a specific schedule or a schedule name prefix.」と書いており、指定するのはスケジュールグループのARNです。スケジュール単位のARNを書くと条件に一致せず、引き受けに失敗します。グループ名に * を使うときは条件演算子を StringEquals から ArnLike に替えます。
スケジュールを作る側(CIのロールや開発者のIAMユーザー)には、scheduler:CreateSchedule に加えて実行ロールを渡す iam:PassRole が必要です。公式のアイデンティティベースのポリシー例では、iam:PassedToService を scheduler.amazonaws.com に限定した書き方が示されています。CreateScheduleが AccessDeniedException で落ちるとき、Scheduler側の権限に加え、実行ロールに対するPassRoleの許可も確認します。
テンプレートターゲットの対応サービス
主要サービスの代表的なAPI操作は、リソースのARNを渡すだけで呼び出せます。一部のターゲットは追加の必須パラメータを伴います。テンプレートターゲットの一覧にある12種は次のとおりです。
| サービス | 呼び出されるAPI操作 | 追加の必須パラメータ |
|---|---|---|
| Lambda | Invoke | なし |
| Step Functions | StartExecution | なし |
| Amazon SQS | SendMessage | なし(FIFOはMessageGroupId) |
| Amazon SNS | Publish | なし |
| Amazon ECS | RunTask | TaskDefinitionArn |
| EventBridge | PutEvents | DetailType / Source |
| Kinesis | PutRecord | PartitionKey |
| Firehose | PutRecord | なし |
| CodeBuild | StartBuild | なし |
| CodePipeline | StartPipelineExecution | なし |
| Amazon Inspector | StartAssessmentRun | なし |
| SageMaker AI | StartPipelineExecution | なし |
EventBridgeのPutEventsをテンプレートターゲットにする場合、クロスリージョン配信はできません。別リージョンのイベントバスへ送るには、送信先リージョン側にスケジュールを作ります。
ユニバーサルターゲットによるEC2の定時停止
テンプレートに無いAPIは、270を超えるサービス・6,000を超えるAPI操作を対象とするユニバーサルターゲットで呼び出します。ARNの形式は arn:aws:scheduler:::aws-sdk:サービス:APIアクション で、Input にはそのAPIのリクエストパラメータをJSONで書きます(Using universal targets)。代表的な用途が、開発環境のEC2を夜間と週末に止める構成です。Lambdaを挟まずに StopInstances を直接呼べます。
# 平日20時(日本時間)に開発用EC2を停止する
aws scheduler create-schedule \
--name stop-dev-ec2 \
--schedule-expression "cron(0 20 ? * MON-FRI *)" \
--schedule-expression-timezone "Asia/Tokyo" \
--flexible-time-window '{"Mode":"OFF"}' \
--target '{
"RoleArn": "arn:aws:iam::123456789012:role/scheduler-ec2-role",
"Arn": "arn:aws:scheduler:::aws-sdk:ec2:stopInstances",
"Input": "{\"InstanceIds\":[\"i-0123456789abcdef0\"]}"
}'
起動側は同じ形で ec2:startInstances を平日8時などに置き、実行ロールには ec2:StopInstances と ec2:StartInstances を対象インスタンスに限って許可します。
ARNには2つの罠があります。1つ目、サービス はエンドポイントのプレフィックスではなくAWS SDKのサービス識別子です。Amazon Cognito Identity Providerは cognito-idp ではなく cognitoidentityprovider を指定します。2つ目、APIアクション は先頭が小文字のcamelCaseで、StopInstances ではなく stopInstances と書きます。
さらに、読み取り系のAPIはターゲットにできません。次のプレフィックスで始まる操作はすべて非対応です。
get, describe, list, poll, receive, search, scan, query, select,
read, lookup, discover, validate, batchGet, batchDescribe, batchRead,
transactGet, adminGet, adminList, testMigration, retrieve,
testConnection, translateDocument, isAuthorized, invokeModel
SQSの GetQueueUrl は get 始まりなので指定できず、Amazon MQの ListBrokers も使えません。定期的にデータを取得したい要件は、取得処理を書いたLambda関数(AWS Lambdaとは?仕組み・料金体系とコールドスタート対策・採用判断を実装者目線で解説)をターゲットにする形へ組み替えます。
コンテキスト属性によるメタデータ受け渡し
ターゲットへ渡す Input(最大256KB)に次のキーワードを書くと、起動時に実際の値へ置換されます。
| キーワード | 置換される値 | 例 |
|---|---|---|
| <aws.scheduler.schedule-arn> | スケジュールのARN | arn:aws:scheduler:… |
| <aws.scheduler.scheduled-time> | 起動予定時刻 | 2022-03-22T18:59:43Z |
| <aws.scheduler.execution-id> | 起動試行ごとの一意ID | d32c5kddcf5bb8c3 |
| <aws.scheduler.attempt-number> | 試行回数のカウンタ | 1 |
実務で効くのは scheduled-time と execution-id の組み合わせです。前者を処理対象日として渡せば、リトライで遅れて実行された処理も本来の対象日で動きます。後者は呼び出し試行ごとの識別に使います。リトライを同じ起動として関連付けるには、スケジュールARNと起動予定時刻を組み合わせます。attempt-number をペイロードに含めておけば、リトライ時だけ通知を抑制する分岐も書けます。
Scheduler APIとSDKによるスケジュール操作
APIの全12操作
| 操作 | 対象 | 用途 |
|---|---|---|
| CreateSchedule | スケジュール | 作成 |
| GetSchedule | スケジュール | 定義の取得 |
| UpdateSchedule | スケジュール | 定義の全置き換え |
| DeleteSchedule | スケジュール | 削除 |
| ListSchedules | スケジュール | 一覧取得 |
| CreateScheduleGroup | グループ | 作成 |
| GetScheduleGroup | グループ | 取得 |
| DeleteScheduleGroup | グループ | 削除(所属スケジュールも削除) |
| ListScheduleGroups | グループ | 一覧取得 |
| ListTagsForResource | タグ | 一覧取得 |
| TagResource | タグ | 付与(グループのみ) |
| UntagResource | タグ | 削除 |
UpdateScheduleは部分更新ではなく全項目の置き換えです。省略したフィールドは既定値に戻るため、GetScheduleで現在の定義を取得し、変更点だけ差し替えてから渡す実装にします。
スケジュールグループの扱いにも、API表からは読み取りにくい性質が2つあります。1つは、DeleteScheduleGroupを呼ぶとグループが DELETING 状態になり、所属するスケジュールを削除し終えてから消えることです。検証環境のスケジュールを一括で片付けるには便利ですが、本番のグループ名を誤って渡すと全件が消えます。もう1つは、TagResourceの対象がスケジュールグループのARNに限られ、個々のスケジュールにはタグを付けられないことです。環境やテナントごとにコスト配分やIAM条件で分けたいなら、その単位でグループを作ります。
AWS CLIでのスケジュール作成
CLI例は東京リージョンを使用する設定を前提とします。別リージョンが既定の場合は、各コマンドに --region ap-northeast-1 を追加してください。例示のアカウントIDとリソースARNは実環境の値に置き換え、実行ロール・Lambda関数・DLQを事前に用意します。
aws scheduler create-schedule \
--name nightly-batch \
--group-name default \
--schedule-expression "cron(0 9 * * ? *)" \
--schedule-expression-timezone "Asia/Tokyo" \
--flexible-time-window '{"Mode":"FLEXIBLE","MaximumWindowInMinutes":15}' \
--target '{
"RoleArn": "arn:aws:iam::123456789012:role/scheduler-exec-role",
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:function:nightly-batch",
"Input": "{\"scheduledTime\":\"<aws.scheduler.scheduled-time>\"}",
"RetryPolicy": {"MaximumRetryAttempts":3,"MaximumEventAgeInSeconds":3600},
"DeadLetterConfig": {"Arn":"arn:aws:sqs:ap-northeast-1:123456789012:scheduler-dlq"}
}'
RetryPolicy と DeadLetterConfig の値の決め方は、後述の「失敗の検知」の章で扱います。
boto3での操作
import json
import boto3
# サービス名は "events" ではなく "scheduler"
scheduler = boto3.client("scheduler", region_name="ap-northeast-1")
resp = scheduler.create_schedule(
Name="nightly-batch",
ScheduleExpression="cron(0 9 * * ? *)",
ScheduleExpressionTimezone="Asia/Tokyo",
FlexibleTimeWindow={"Mode": "FLEXIBLE", "MaximumWindowInMinutes": 15},
Target={
"RoleArn": "arn:aws:iam::123456789012:role/scheduler-exec-role",
# テンプレートターゲット: Lambda関数のARNをそのまま渡す
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:function:nightly-batch",
"Input": json.dumps({"scheduledTime": "<aws.scheduler.scheduled-time>"}),
"RetryPolicy": {"MaximumRetryAttempts": 3, "MaximumEventAgeInSeconds": 3600},
},
)
print(resp["ScheduleArn"])
クライアント名は scheduler です。boto3.client("events") はEventBridge本体のクライアントで、create_schedule は生えていません。
命名にも制約があります。スケジュール名は1〜64文字で、使える文字は [0-9a-zA-Z-_.] のみです。テナントIDやメールアドレスをそのまま名前にすると、記号でValidationExceptionになります。作成リクエストを安全に再送するには、同じ ClientToken(1〜64文字)を再利用しますが、こちらの許容文字は [a-zA-Z0-9-_] でドットが使えません。スケジュール名用の命名規則をそのまま流用すると、ドットを含む値で落ちます。
AWS SDK for JavaScript v3(@aws-sdk/client-scheduler)
Node.jsでは @aws-sdk/client-scheduler(2026年11月時点のnpm最新は3.1161.0)を使います。パラメータ名はAPIと同じPascalCaseです。
// create-schedule.mjs(トップレベルawaitのためESMで実行)
import { SchedulerClient, CreateScheduleCommand } from "@aws-sdk/client-scheduler";
const client = new SchedulerClient({ region: "ap-northeast-1" });
const res = await client.send(new CreateScheduleCommand({
Name: "nightly-batch",
ScheduleExpression: "cron(0 9 * * ? *)",
ScheduleExpressionTimezone: "Asia/Tokyo",
FlexibleTimeWindow: { Mode: "OFF" },
Target: {
Arn: "arn:aws:lambda:ap-northeast-1:123456789012:function:nightly-batch",
RoleArn: "arn:aws:iam::123456789012:role/scheduler-exec-role",
Input: JSON.stringify({ scheduledTime: "<aws.scheduler.scheduled-time>" }),
},
}));
console.log(res.ScheduleArn);
同じ名前のスケジュールが同じグループに既にあると ConflictException が返ります。デプロイのたびに作り直す処理なら、先にGetScheduleで存在を確かめてUpdateScheduleへ分岐させます。
スケジュールの手動実行と動作確認
「作ったスケジュールを今すぐ1回動かして確認したい」という要件に対し、EventBridge Schedulerには専用のAPIがありません。前掲の12操作のとおり、即時実行やテスト起動に相当する操作は定義されていないためです。実務ではat式による正攻法と、ターゲット直接呼び出しによるデバッグ用の手段を使い分けます。
at式の単発スケジュールによる実行(推奨)
1〜2分後を指す単発スケジュールを作り、実行後に自動削除させます。本番と同じ実行ロール・同じターゲット定義・同じ入力を通るので、権限不足やInput形式の誤りをそのまま検出できます。
# 2分後に1回だけ実行し、完了後にスケジュールを自動削除する
aws scheduler create-schedule \
--name nightly-batch-manual-test \
--schedule-expression "at($(date -u -v+2M '+%Y-%m-%dT%H:%M:%S'))" \
--action-after-completion DELETE \
--flexible-time-window '{"Mode":"OFF"}' \
--target '{
"RoleArn": "arn:aws:iam::123456789012:role/scheduler-exec-role",
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:function:nightly-batch",
"Input": "{\"scheduledTime\":\"<aws.scheduler.scheduled-time>\"}"
}'
at式のタイムスタンプにタイムゾーンは含められないため、--schedule-expression-timezone を指定しない場合はUTCで解釈されます。上のコマンドは date -u でUTCの2分後を生成しています(macOSの書き方です。GNU coreutilsの環境では date -u -d '+2 minutes' '+%Y-%m-%dT%H:%M:%S' に読み替えてください)。--action-after-completion DELETE を付け忘れると、テスト用のスケジュールがクォータを消費したまま残ります。
ターゲットAPIの直接呼び出しと検証範囲の限界
aws lambda invoke \
--function-name nightly-batch \
--payload '{"scheduledTime":"2026-11-03T00:00:00Z"}' \
--cli-binary-format raw-in-base64-out \
/tmp/out.json
この方法で確認できるのは関数側のロジックだけです。スケジュール式の解釈も、実行ロールの権限も、Inputの受け渡しも検証していません。「手で叩けば動くのに定時に動かない」場合は、この差分(実行ロールに lambda:InvokeFunction が無い、Inputが期待するJSONになっていない)が原因です。関数のデバッグ中はこちらで回し、結合確認は前項のat式で行う、と切り分けます。
失敗の検知:リトライ・DLQ・CloudWatchメトリクス
Schedulerの既定の構成では、ターゲットの呼び出しが失敗しても誰にも通知されません。ターゲットAPIへの配信失敗を検知するため、Schedulerのリトライ・DLQ・メトリクスのアラームを設定します。Lambdaのテンプレートターゲットは非同期呼び出しなので、受付後の関数内エラーはLambda側のメトリクスや失敗時の送信先で別途監視します。
リトライポリシーとDLQの設定条件
RetryPolicy の指定範囲は、MaximumRetryAttempts が0〜185回、MaximumEventAgeInSeconds が60〜86400秒です。リトライは指数バックオフで行われ、回数か経過時間のどちらかの上限に達した時点で打ち切られます。日次バッチなら、翌日の起動と重ならないよう MaximumEventAgeInSeconds を数時間以内に抑えます。
打ち切られた起動を残すには DeadLetterConfig にSQSキューを指定します。DLQの設定ページから読み取れる条件は次の3つです。
- 標準キューのみ:「EventBridge Scheduler does not support using a FIFO queue as your schedule’s DLQ.」と明記されています。
- 権限は実行ロールに付ける:DLQへの送信は実行ロールで行われるため、実行ロールに
sqs:SendMessageが必要です。 - 別アカウントのキューも指定できる:コンソールでは一覧に出ないため、キューのARNを直接入力します。この場合は実行ロールの権限に加え、キュー側のキューポリシーでもそのロールからの送信を許可します。
DLQをKMSのカスタマーマネージドキーで暗号化している場合は、もう1つ条件があります。Schedulerのトラブルシューティングのページは、キーポリシーで scheduler.amazonaws.com に kms:Decrypt と kms:GenerateDataKey を許可する例を示しています。これが無いとDLQへの送信が失敗し、次の章の InvocationsFailedToBeSentToDeadLetterCount に現れます。
DLQを指定しない場合、失敗した起動のペイロードはどこにも残りません。残るのは後述のメトリクスの件数だけです。キューの可視性タイムアウトや保持期間の設計はAmazon SQSとは?FIFOキューと標準キューの違い・重複排除・可視性タイムアウトとDLQの設計【2026年10月】で扱っています。
DLQメッセージ属性による失敗原因の切り分け
DLQに届くメッセージの本文は、ターゲットに渡すはずだった Input です。原因はメッセージ属性に入ります。
| 属性 | 内容 |
|---|---|
| ERROR_CODE | エラーコード |
| ERROR_MESSAGE | ターゲットが返したエラーの詳細 |
| EXHAUSTED_RETRY_CONDITION | 打ち切りの条件(回数か経過時間か) |
| RETRY_ATTEMPTS | 実施したリトライ回数 |
| SCHEDULED_TIME | 起動予定時刻 |
| SCHEDULE_ARN / TARGET_ARN | スケジュールとターゲットのARN |
| EXECUTION_ID | 起動の一意ID |
| IS_PAYLOAD_TRUNCATED | 本文が切り詰められたか |
属性は receive-message に --message-attribute-names All を付けないと返りません。SCHEDULED_TIME があるので、DLQから取り出したメッセージを本来の対象日で再処理する仕組みも組めます。
CloudWatchメトリクスとアラームの置き方
Schedulerは名前空間 AWS/Scheduler にメトリクスを出します(Monitoring with CloudWatch)。アラームに使うのは次の5つです。
| メトリクス | 出る条件 |
|---|---|
| TargetErrorCount | ターゲットが例外を返した |
| TargetErrorThrottledCount | ターゲット側のAPIスロットリング |
| InvocationThrottleCount | Schedulerの呼び出しクォータ超過 |
| InvocationDroppedCount | リトライを使い切って破棄した |
| InvocationsFailedToBeSentToDeadLetterCount | DLQへの送信にも失敗した |
最優先は InvocationDroppedCount と InvocationsFailedToBeSentToDeadLetterCount の「1件以上」でのアラームです。前者はリトライポリシーの上限に達してターゲットへの呼び出しを終了したこと、後者はDLQへの送信失敗を示します。DLQ送信失敗の原因には、キュー削除や権限不足などがあります。後者にはエラーコード付きの派生メトリクス(キューが存在しない場合は InvocationsFailedToBeSentToDeadLetterCount_AWS.SimpleQueueService.NonExistentQueue)も出るので、原因まで特定できます。
設計上の制約は、ディメンションが ScheduleGroup しかないことです。スケジュール単位のメトリクスは無く、同じグループの中で「どのスケジュールが失敗したか」はメトリクスからは分かりません。重要な処理を個別に監視したいなら、その処理だけのスケジュールグループを作るか、DLQの SCHEDULE_ARN 属性で特定します。また公式は、メトリクスの配信をベストエフォートと説明しています。課金や監査に使う正確な件数が要るなら、ターゲット側のログで数えてください。
クォータの監視には、2026年2月17日に追加が発表されたリソース数のメトリクスが使えます。名前空間 AWS/Usage の ResourceCount で、Resource ディメンションに ApproximateSchedule(スケジュール数の概数)と ApproximateScheduleGroup を指定します。DELETE を付け忘れた単発スケジュールが溜まっていく状況は、この値の右肩上がりで気づけます。
IaCでの定義(CloudFormation・Terraform・CDK)
CloudFormationのAWS::Scheduler::Scheduleによる定義
Resources:
NightlyBatchSchedule:
Type: AWS::Scheduler::Schedule
Properties:
Name: nightly-batch
GroupName: default
State: ENABLED
ScheduleExpression: cron(0 9 * * ? *)
ScheduleExpressionTimezone: Asia/Tokyo
FlexibleTimeWindow:
Mode: FLEXIBLE
MaximumWindowInMinutes: 15
Target:
Arn: !GetAtt NightlyBatchFunction.Arn
RoleArn: !GetAtt SchedulerExecutionRole.Arn
RetryPolicy:
MaximumRetryAttempts: 3
MaximumEventAgeInSeconds: 3600
スケジュールグループは AWS::Scheduler::ScheduleGroup で別リソースとして定義します。グループ名を省略すると default グループに入り、前述のとおりタグ・メトリクス・信頼ポリシーの条件をグループ単位でしか分けられないため、分離の単位が最初から1つに固定されます。テンプレートの基本構文はAWS CloudFormationとは?テンプレートの書き方・スタック操作と更新で消える設定の防ぎ方で確認できます。
Terraformのaws_scheduler_scheduleによる定義と対応バージョン
resource "aws_scheduler_schedule" "nightly_batch" {
name = "nightly-batch"
group_name = "default"
schedule_expression = "cron(0 9 * * ? *)"
schedule_expression_timezone = "Asia/Tokyo"
action_after_completion = "DELETE"
state = "ENABLED"
end_date = "2027-01-01T00:00:00Z"
flexible_time_window {
mode = "FLEXIBLE"
maximum_window_in_minutes = 15
}
target {
arn = aws_lambda_function.nightly_batch.arn
role_arn = aws_iam_role.scheduler_exec.arn
retry_policy {
maximum_retry_attempts = 3
maximum_event_age_in_seconds = 3600
}
dead_letter_config {
arn = aws_sqs_queue.scheduler_dlq.arn
}
}
}
flexible_time_window と target は必須ブロックです。action_after_completion はAWS provider 6.14.0(2025年9月18日リリース)で追加された引数で、それより前のバージョンでは Unsupported argument になります(2026年11月時点の最新は6.71.0)。定期スケジュールへ DELETE を指定する場合は、上の例のように end_date の併記が必要です。
name を省略するとTerraformが terraform- で始まるランダムな名前を割り当てます。name と group_name はいずれも変更時にリソースの再作成が走る属性なので、命名規則は最初に固めておきます。ルール・ターゲット・権限を含むEventBridge全体のTerraform実装はTerraform EventBridgeの実装手順:ルール・ターゲット・Schedulerと権限のHCL例にまとめています。
AWS CDKの安定版モジュール(aws-cdk-lib/aws-scheduler)による定義
CDKのSchedulerモジュールは長らくalpha扱いでしたが、@aws-cdk/aws-scheduler-alpha は 2.186.0-alpha.0(2025年3月27日公開)を最後に「安定化してaws-cdk-libへ移動した」として非推奨になりました。現在は aws-cdk-lib/aws-scheduler と aws-cdk-lib/aws-scheduler-targets を直接importします(2026年11月時点のaws-cdk-lib最新は2.275.0)。
import { Duration, TimeZone } from 'aws-cdk-lib';
import { Schedule, ScheduleExpression, TimeWindow } from 'aws-cdk-lib/aws-scheduler';
import { LambdaInvoke } from 'aws-cdk-lib/aws-scheduler-targets';
// Stackのコンストラクタ内。nightlyBatchFn は lambda.IFunction、schedulerDlq は sqs.IQueue
new Schedule(this, 'NightlyBatch', {
scheduleName: 'nightly-batch',
schedule: ScheduleExpression.cron({
minute: '0',
hour: '9',
timeZone: TimeZone.ASIA_TOKYO,
}),
target: new LambdaInvoke(nightlyBatchFn, {
retryAttempts: 3,
maxEventAge: Duration.hours(1),
deadLetterQueue: schedulerDlq,
}),
timeWindow: TimeWindow.flexible(Duration.minutes(15)),
});
alpha時代のコードはimportパスの変更でほぼ移行できますが、@aws-cdk/aws-scheduler-alpha と両方からimportすると同名クラスが別の型になり型エラーになります。import元はaws-cdk-libへ寄せきってください。CDK全体の位置づけはAWS CDK(cdk)とは?スタックの仕組みとcdk deployの使い方、CloudFormation・Terraformとの違いを参照してください。
クォータ・スループットと東京リージョンの料金
リージョンで変わるクォータ
クォータはリージョン単位で、主要リージョンとそれ以外で値が違います。次はap-northeast-1(東京)を含む主要11リージョンの既定値です(Quotas for EventBridge Scheduler)。
| クォータ | 主要リージョン | その他のリージョン | 引き上げ |
|---|---|---|---|
| スケジュール数 | 10,000,000 | 10,000,000 | 可(数十億まで) |
| スケジュールグループ数 | 500 | 500 | 可 |
| CreateSchedule | 5,000 TPS | 250 TPS | 可(数万TPSまで) |
| Update / Delete / GetSchedule | 1,000 TPS | 250 TPS | 可 |
| ListSchedules | 50 TPS | 50 TPS | 可 |
| 呼び出しスロットル | 1,000 TPS | 500 TPS | 可(数万TPSまで) |
| グループ系API | 10 TPS | 10 TPS | 可 |
| ListTagsForResource | 10 TPS | 10 TPS | 可 |
| TagResource / UntagResource | 1 TPS | 1 TPS | 可 |
主要リージョンは us-east-1、us-east-2、us-west-2、ap-northeast-1、ap-south-1、ap-southeast-1、ap-southeast-2、eu-central-1、eu-west-1、eu-west-2、sa-east-1 です。大阪リージョン(ap-northeast-3)はこの一覧に含まれないため、CreateScheduleが250 TPSになります。数万件のスケジュールを一括投入する初期移行では、この差が所要時間に直結します。
呼び出しスロットルの超過は、他のAPIスロットリングと挙動が異なります。リクエストが拒否されるのではなく、起動が遅延します。同時刻に大量のスケジュールを集中させている構成では「原因不明の実行遅れ」として現れるので、前章の InvocationThrottleCount を監視し、フレックスタイムウィンドウで分散させるか上限引き上げを申請してください。
東京リージョンの料金
料金はスケジュールの保持数ではなく呼び出し回数で決まります。AWSのPrice List API(東京リージョン)の値は次のとおりです(2026年9月24日公開版)。
| 区分 | 東京(ap-northeast-1) | バージニア北部(us-east-1) |
|---|---|---|
| 月1,400万回まで(全リージョン合算) | 無料 | 無料 |
| 超過分(100万回あたり) | 1.25 USD | 1.00 USD |
30日間、1分ごとに起動するスケジュールは43,200回です。無料枠はGovCloudを除く全リージョンの利用分で合算されるため、ほかの利用がなければ300本強を賄えます。たとえば1分間隔のスケジュールを東京で1,000本動かすと30日で約4,320万回、無料枠を引いた約2,920万回分で東京なら約36.5 USDです。料金ページの英語版に載っている1.00 USDをそのまま東京の見積もりに使うと、超過分を2割低く見積もることになります。
呼び出し料金とは別に、ターゲット側(Lambdaの実行時間、SQSのリクエストなど)の料金がかかります。ペイロードをカスタマーマネージドキー(KMS)で暗号化する場合は、暗号化の対象はペイロード(最大256KB)だけで、キーの月額料金とAPI呼び出し料金も加わります。EventBridge本体のイベントバスの課金体系は別なので、内訳はAmazon EventBridgeの料金|東京の単価・無料になる条件と新しいイベントバスの課金【2026年10月】で確認してください。夜間停止の自動化を含め、AWS環境の構築や運用設計をまとめて任せたい場合はインフラ構築(AWS・Google Cloud・Azure)で相談を受け付けています。
よくある質問
EventBridge Schedulerのスケジュールを手動実行できますか?
即時実行のAPIはありません。実務では、1〜2分後を指すat式の単発スケジュールを ActionAfterCompletion=DELETE 付きで作成します。ターゲットのAPIを直接呼ぶ方法では、実行ロールの権限やInputの受け渡しを検証できません。
EventBridgeのスケジュールされたルールとの違いは何ですか?
ルールはイベントバスあたり300件・1ルールに最大5ターゲット・UTC固定です。Schedulerはリージョンあたり1,000万件・1スケジュールに1ターゲットで、IANAタイムゾーンの指定とat式による単発実行に対応します。AWSはスケジュールされたルールをレガシー機能と位置づけています。
boto3でEventBridge Schedulerを操作するクライアント名は何ですか?
boto3.client("scheduler") です。boto3.client("events") はEventBridge本体のクライアントで create_schedule を持ちません。CLIも aws scheduler と aws events でコマンド体系が分かれています。
aws.scheduler.scheduled-timeには何が入りますか?
そのスケジュールの起動予定時刻が入ります。実際に呼び出された時刻ではないため、リトライやフレックスタイムウィンドウで遅れて実行されても値は変わりません。処理対象日の判定にはこちらを使います。
EventBridge Schedulerの料金はいくらですか?
GovCloudを除く全リージョン合算で月1,400万回の呼び出しまで無料で、超過分は東京リージョンで100万回あたり1.25 USD、バージニア北部で1.00 USDです。スケジュールの保持数では課金されず、ターゲット側の料金は別にかかります。
関連記事
- Amazon EventBridgeとは?仕組み・料金とCLI・Pythonでの実装手順、新Custom Event Busとの違いを解説【2026年版】
- Amazon EventBridgeの料金|東京の単価・無料になる条件と新しいイベントバスの課金【2026年10月】
- EventBridgeからSQS・Lambdaへつなぐ設定|キューポリシー・FIFO・部分バッチ応答とDLQ【2026年10月】
- AWS Step Functionsとは?ステートマシンの仕組み・料金と2種のワークフロー・採用判断を実装者目線で解説
- Cloud Schedulerとは?GCPのフルマネージドcronの仕組み・3つのターゲットとリトライ・料金、Cloud Tasksとの違いを実装者目線で解説