1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cloudflare Workers の cron 1本で複数ジョブを回す(毎分tick+時刻分岐)

1
Posted at

Cloudflare Workers で定期実行を組もうとすると、無料プランの cron トリガー上限(アカウント単位で5本) に最初に当たります。1サービスで用途ごとに cron を切ると5本はすぐ埋まり、同じアカウントで別サービスも動かしたい、となると足りません。

対処はシンプルで、cron を毎分1本に集約し、scheduled() の中で時刻を見てジョブを振り分ける。これで6種類の定期処理を回しても、消費する cron は1本だけになります。個人で作った価格ウォッチャーでこの形にしたので、要点をまとめます。

cron は毎分1本、tick の中で時刻分岐

cron 式は * * * * *(毎分)1本だけ登録し、ハンドラの中で「今この分は何をやるか」を分岐します。

export const CRON_TICK = '* * * * *'; // wrangler.toml の crons と一致させる

export async function runScheduledTick(env: Env, now: Date): Promise<void> {
  if (isPatrolTick(now))       await runPatrol(env, now);        // 5分毎
  if (isKaidokiDayTick(now))   await runKaidokiDay(env, now);    // JST00:00
  if (isHousekeepingTick(now)) await runHousekeeping(env, now);  // JST03:30
  await runDispatchCron(env, now);                               // 毎分(送信)
}
// Workers エントリ
export default {
  async scheduled(_e: ScheduledController, env: Env, ctx: ExecutionContext) {
    ctx.waitUntil(runScheduledTick(env, new Date()));
  },
};

毎分の tick ごとに、その分に該当するジョブだけが走ります。用途を足しても cron は増えません。

分岐の述語は UTC で書く

scheduled に渡る時刻は UTC です。ローカルタイムのつもりで書くとズレるので、Date の UTC メソッドで書き、日本時間で動かしたいものは JST = UTC+9 で換算します。

export const isPatrolTick       = (n: Date) => n.getUTCMinutes() % 5 === 0;
export const isKaidokiDayTick   = (n: Date) => n.getUTCHours() === 15 && n.getUTCMinutes() === 0;  // JST00:00
export const isHousekeepingTick = (n: Date) => n.getUTCHours() === 18 && n.getUTCMinutes() === 30; // JST03:30

述語を関数に切り出すと、runScheduledTick は「該当したら呼ぶ」を並べるだけで読めます。テストは new Date('2026-07-25T18:30:00Z') のような UTC 文字列を渡せば分岐を単体で確認できます。

信頼性は専用 cron と変わらない

「毎分1本にまとめると日次処理が不安定になるのでは」と思うかもしれませんが、依存先が同じなので信頼性は変わりません。

「UTC18:30 に発火する専用 cron」も「毎分 cron の UTC18:30 の発火で時刻判定する」も、どちらも Cloudflare がその分に cron を発火させること に等しく依存しています。発火が飛べば専用 cron も飛ぶし、毎分 tick が来ていれば時刻判定も成立します。集約で増える不確実性はありません。

運用で一点だけ効くのは、wrangler.toml[triggers] crons とコードの cron 定数を 1文字違わず一致させる ことです。ズレると発火しない/余計に登録されるので、両者を突き合わせるテストを1本置くと安全です。

無料枠のサブリクエスト(50)にバッチを収める

もう一つの無料枠制限として、1回の実行あたりの外向き fetch(サブリクエスト)は50本までです。cron を集約しても、1 tick の処理がこれを超えると失敗します。だからジョブごとに「1件で何サブリクエスト使うか」からバッチサイズを逆算します。

// 送信: 1件=送信直前の再照会 + 配信 で2サブリクエスト → バッチは半分に
const batchSize = Math.floor(PUSH_BATCH_SIZE / 2);
await runDispatch(deps, batchSize, now);

巡回のように1件1リクエストなら40件程度に、送信のように1件2サブリクエストなら半分に。1回で捌き切れない取り込みは、対象をローテーションで数件ずつに割り、数日かけて全体を一周させます。50本の壁は「一度に全部やらない」で越えます。


同じ tick で投入したジョブを同じ実行で拾う呼び出し順序の設計や、重い日次処理を別時刻に散らす運用、この cron が回している通知配送(ログイン不要の Web Push)の中身は、Aulvem 本家にまとめました → Aulvem|Workers の cron 1本で複数ジョブを回す。動いているものはヤスゴロで触れます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?