本文へ移動
runlot

定期実行

runlot.json で `triggers.crons` を宣言すると、worker の scheduled ハンドラーがそのスケジュールで実行されます。

runlot.json に triggers を追加すると、worker の scheduled ハンドラーが指定した時刻に実行されます。

runlot.json
{
  "name": "my-app",
  "main": "src/index.ts",
  "triggers": { "crons": ["30 18 * * *"] }
}
src/index.ts
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    return new Response("hello");
  },
  async scheduled(controller: ScheduledController, env: Env, ctx: ExecutionContext) {
    // controller.scheduledTime is the time this run was due for, not the current time.
    // controller.cron is the expression that fired.
    await rebuild(env);
  },
};

runlot deploy は登録しようとしているスケジュールを表示するため、実行前に確認できます。

Scheduled execution (UTC): 30 18 * * *

スケジュールの命名

triggers.names で、式をキーにしてスケジュールに名前を付けます。ダッシュボードと runlot cron は、各スケジュールと各実行の横にその名前を表示します。

runlot.json
{
  "triggers": {
    "crons": ["30 18 * * *", "*/2 * * * *"],
    "names": { "30 18 * * *": "nightly recompute", "*/2 * * * *": "queue sweep" }
  }
}

すべてのキーが crons に含まれている必要があります。名前は1行で、80バイト以内です。名前は省略できます。名前のないスケジュールは式で表示されます。

式

minute hour day-of-month month day-of-week の5つのフィールドをUTCで評価します。

形式意味
*すべての値
55のみ
1-51から5まで
*/1515ごとの値
0,300と30
jan, mon月と曜日の名前

日曜日は 0 です(7 も受け付けられます)。day-of-month と day-of-week の両方が制限されている場合、どちらかに一致すれば実行されます — これは cron の従来からの挙動であり、0 0 1 * 1 は「月の1日、またはすべての月曜日」を意味します。

式はデプロイ時にパースされます。不正な形式のもの、または絶対に発火しないもの(0 0 30 2 * — 2月30日)は、該当フィールド名を示す400で拒否されます。受理されても一度も実行されないスケジュールは、壊れたデプロイと区別がつかなくなるため、受理しません。

制限

無料プロ
粒度1分1分
組織あたりのスケジュール数5250
プロジェクトあたりのスケジュール数55
実行ごとの実時間、1時間未満のスケジュール30秒30秒
実行ごとの実時間、1時間以上のスケジュール5分5分

上限を超えた実行はキャンセルされ、失敗として記録されます。頻繁なスケジュールほど予算が小さいのは意図的です。コストがかかるのはスケジュールの保存ではなく、2分ごとにプロジェクトを起動することだからです。

想定しておくこと

時刻は目安です。 実行は指定した分ちょうどではなく、その分以降に開始します。秒単位の正確さに依存する仕組みは作らないでください。

実行中のものは次の実行をブロックします。 2分おきにスケジュールされたジョブが3分かかる場合、実行中に到来した分は後ろに並ばずに破棄され、overlapという理由で記録されます。このルールがなければ、プロジェクトが処理できる速さを超えて作業が積み重なってしまいます。

大きく遅れた実行は破棄されます。 スケジュールがしばらく処理されなかった場合、見逃した分をすべて再生するのではなく、最新の回を一度だけ実行します。そうしないと、*/2 * * * * で1時間ダウンした場合に30回連続で発火してしまいます。

停止(park)中のプロジェクトは起こされます。 プロジェクトはアイドル状態になるとプロセスを停止します(停止と再開)。スケジュールはまずプロジェクトを起こしてから実行します。起動処理も実行に含まれるため、アイドル状態のプロジェクトの最初のスケジュール実行は数百ミリ秒余分にかかります。

コールド状態のプロジェクトは実行が遅れます。 長期間アイドル状態が続くと、プロジェクトのデータがマシンから退避されることがあります(コールド状態と再開)。現在、スケジュールにはプロジェクトを呼び戻す機能はありません。実行は、別の何かがプロジェクトを復帰させた後に行われます。そのプロジェクトに触れるのがスケジュールだけである場合は、1時間に1回以上の頻度に保ってください。

実行の確認

記録はプロジェクトのスケジュール実行タブにあります。デプロイタブの隣にあり、宣言した各スケジュールの次回実行時刻、直近24時間の状況、そして過去の実行の表を表示します。いつ始まったか、どの式が発火したか、どう終わったか、どれだけかかったか、実行されなかった場合はその理由まで確認できます。

同じ記録はターミナルからも確認できます。

runlot cron
0 * * * *	next 2026-09-27T10:00:00Z	last failed (exception)

Last 24 hours: 20 ok, 4 failed.

2026-09-27T09:00:00Z	0 * * * *	failed (exception)	141ms	TypeError: Invalid redirect value, must be one of "follow" or "manual"

プロジェクトが起動している間は、ログにも1行ずつ残ります。

runlot logs
[runlot] Scheduled run 30 18 * * * finished (1.2s)

**ハンドラーが例外を投げた場合、エラーは両方に残ります。**メッセージは実行行の末尾とログに現れ、ログにはスタックも一緒に載ります。

[stderr] Uncaught (in scheduled) TypeError: Invalid redirect value, must be one of "follow" or "manual"
[stderr] TypeError: Invalid redirect value, must be one of "follow" or "manual"
[stderr]     at Object.scheduled (index.js:42:11)

そのため、失敗したスケジュールを再現して原因を探す必要はありません。メッセージはrunlot cronで、その周辺のフレームはrunlot logsで読めます。

ログはバッファなので古い行から押し出されます。タブの履歴は無料プランで30日、Proプランで365日保持されます。

実行の終わり方は4通り

成功ハンドラーが実行され、返りました。
失敗ハンドラーが例外を投げたか、workerがscheduledをエクスポートしていません。表示される理由はランタイム自身の値(exceptionなど)で、その隣にコードが投げたメッセージが並びます。
エラー実行がハンドラーまで届きませんでした。1回あたりの制限を超えた(timeout)、workerに到達できなかった(fire_failed)、アイドル状態のプロジェクトが起動できなかった(wake_failed)のいずれかです。これは利用者側ではなく当社側の問題です。
スキップスケジュールは到来しましたが、実行しないと判断しました: overlap(直前の実行がまだ進行中)、too_late(予定時刻を大きく過ぎて到来)、schedule_changed(起動したプロジェクトが、発火しようとしていたものと異なるスケジュールを持っていた)。

失敗とエラーは組織の管理者にメールで通知します。1つのスケジュールにつき1日1通までです。スキップは通知しません。設計どおりの動作であり、それまで通知すると、本当に重要な次のメールを見逃すようになるからです。

mainを指定せずにtriggersをデプロイすることは拒否されます。静的アセットのデプロイには呼び出すハンドラーがないためです。

スケジュールの変更と削除

スケジュールはコードと一緒に移動します。runlot.jsonを編集してデプロイしてください。以前のバージョンにロールバックすると、そのバージョンのスケジュールも復元されます。停止するにはtriggersを削除してデプロイしてください。

対応していないもの

実行を手動でトリガーする方法はありません。オンデマンドで開始する必要がある処理には、ルートを公開し、runlot secret setで発行したトークンで保護してください。

コールド状態のプロジェクトの実行が遅れる点も、上で説明したとおりです。

このページの目次