Skip to content

필사 모드: Cron とスケジュールタスク 2026 — systemd timers / Vercel Cron / AWS EventBridge Scheduler / k8s CronJobs / BullMQ / Sidekiq / Temporal 徹底ガイド

日本語
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

プロローグ — 「cron 回しとけばいいでしょ?」が危うくなった時代

2026 年のあるチームの設計レビュー。

新人「毎日 9 時にレポートメールを送りたいんです。cron でいいですよね?」

シニア「どのホストで?監視は?失敗したら?二回走ったら?マシンが落ちたら?」

新人「……あ。」

この短いやり取りに 2026 年のスケジューリングがすべて詰まっている。cron は 50 年間動き続けてきたが、クラウドネイティブ時代に入ってからは「決まった時間にコマンドを実行する」だけでは到底足りない。ホストの停止、二重実行の競合、失敗通知、リトライ、分散ロック、冪等性、タイムゾーン、サマータイム(DST)——すべてが運用上の罠になった。

2026 年現在、スケジュールタスクは大きく **4 つのカテゴリ** に分かれる。システムレベル(cron、systemd timers、fcron、anacron)、クラウドマネージド(Vercel Cron、EventBridge Scheduler、Cloudflare Workers、GitHub Actions schedule)、分散バックグラウンドキュー(BullMQ、Sidekiq、Celery Beat)、ワークフローエンジン(Airflow、Dagster、Prefect、Temporal、Inngest、Trigger.dev、Hatchet)。そしてその上に監視(Healthchecks.io、Cronitor.io)が乗る。

本記事ではこの地形を一気に整理する。古典的な cron の 5 フィールドから、systemd timers、Vercel Cron、AWS EventBridge Scheduler(2022 年 11 月に CloudWatch Events Rules を置き換え)、k8s CronJobs、BullMQ、Sidekiq、Celery Beat、Temporal Schedules、Hatchet、Quartz、Hangfire、fcron、anacron、Nomad periodic jobs、監視 SaaS まで。韓国のトス・カカオ、日本のメルカリが何をどう使っているかも見る。

1. 2026 年の cron 地図 — システム / クラウド / キュー / ワークフロー

まず全体像。「スケジュールタスク」という一語の下に、まったく異なる道具が並んでいる。

| カテゴリ | 代表的なツール | 適したケース |

| --- | --- | --- |

| システム cron | crond、systemd timers、fcron、anacron | 単一ホストのバックグラウンド整理、ログローテーション |

| クラウドマネージド | Vercel Cron、AWS EventBridge Scheduler、Cloudflare Workers Cron Triggers、GitHub Actions schedule、GitLab schedule pipelines | サーバーレス、CI/CD、インフラ自動化 |

| 分散バックグラウンドキュー | BullMQ、Sidekiq、Celery Beat、RQ、dramatiq、APScheduler、Quartz、Spring @Scheduled、Hangfire | アプリ内のジョブキュー + スケジュール |

| ワークフローエンジン | Airflow、Dagster、Prefect、Temporal Schedules、Inngest Crons、Trigger.dev v3、Hatchet | 多段階データパイプライン、信頼性重視のワークフロー |

| コンテナ | k8s CronJobs、Nomad periodic jobs | コンテナベースのバッチ |

| 監視 | Healthchecks.io、Cronitor.io | デッドマンスイッチ、未受信アラート |

2026 年に共有されているベストプラクティスはこうだ。

1. **単一ホストの一コマンド** なら systemd timers(cron ではなく)。

2. **サーバーレス環境** なら Vercel Cron、EventBridge Scheduler、Cloudflare Cron のいずれかをインフラに合わせて。

3. **アプリ内のバックグラウンド + 定期作業** なら BullMQ / Sidekiq / Celery Beat。

4. **多段階ワークフロー** なら Temporal / Inngest / Trigger.dev / Hatchet(モダン)か Airflow / Dagster / Prefect(伝統)。

5. **何を選んでも Healthchecks.io / Cronitor.io で未受信アラート** を仕掛ける。

このガイドに従えば、2026 年のケースの 99% は片付く。

2. 古典的な cron — 5 フィールド表記、/etc/crontab

cron は 1975 年に Brian Kernighan が書いた Unix のツールだ。50 年間生き残り、ほぼすべての Linux ホストに今もインストールされている。中心の **5 フィールド** から。

┌───────── 分 (0-59)

│ ┌─────── 時 (0-23)

│ │ ┌───── 日 (1-31)

│ │ │ ┌─── 月 (1-12)

│ │ │ │ ┌─ 曜日 (0-7、0 と 7 は日曜)

│ │ │ │ │

* * * * * command-to-execute

よく使うパターン。

毎日 0 時

0 0 * * * /usr/local/bin/backup.sh

毎時 0 分

0 * * * * /usr/local/bin/sync.sh

5 分おき

*/5 * * * * /usr/local/bin/healthcheck.sh

平日 9 時

0 9 * * 1-5 /usr/local/bin/report.sh

毎月 1 日 3 時

0 3 1 * * /usr/local/bin/monthly-billing.sh

cron には 2 種類の crontab がある。

- **ユーザー crontab**: `crontab -e` で編集、`/var/spool/cron/` に保存、ユーザー権限で実行。

- **システム crontab**: `/etc/crontab` や `/etc/cron.d/*` に置き、実行ユーザーを 6 番目のフィールドとして明示する。

/etc/crontab — システム用。user フィールドが追加される。

SHELL=/bin/bash

PATH=/sbin:/bin:/usr/sbin:/usr/bin

m h dom mon dow user command

17 * * * * root cd / && run-parts --report /etc/cron.hourly

25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts /etc/cron.daily )

5 フィールド以外に、一部の cron 実装(Vixie cron、anacron、cronie)は **秒の 6 フィールド** を扱える。ただし標準的な POSIX cron は 5 フィールドしか理解しないことを忘れずに。BullMQ・Quartz・Spring などのライブラリは 6 フィールドや 7 フィールド(年)まで受け付ける。

cron の限界。

1. **監視がない**: 失敗しても誰も気付かない。出力はメールで送られるが、2026 年に root のメールを誰が読んでいるのか。

2. **キャッチアップなし**: ホストが落ちている間に予定された実行は素直に欠落(anacron がこの問題を解く)。

3. **単一ホスト**: 分散ロックがない → 同じ cron を 2 つのホストに入れると 2 回走る。

4. **タイムゾーン**: システムの TZ で動く。UTC でなければ DST(サマータイム)で 1 時間消えるか 2 回走る事故が起きる。

5. **表現力不足**: 「毎月最終平日」のような表現が難しい。

それでも cron は生きている。シンプルさという価値があるからだ。1 行のジョブ、1 つのホスト、監視が明らかに不要なケース(ログローテーション、一時ファイルの掃除)であれば、cron は今でも最適だ。

3. systemd timers — Linux のモダンな代替

systemd が init システムを統一して以降(2010 年代半ば)、**systemd timers** が cron のモダンな代替として定着した。RHEL/CentOS Stream、Ubuntu、Debian、Fedora はすべて systemd がデフォルトだ。

systemd timer は 2 ファイル構成。

/etc/systemd/system/backup.service

[Unit]

Description=Daily backup

[Service]

Type=oneshot

ExecStart=/usr/local/bin/backup.sh

User=backup

Nice=10

IOSchedulingClass=idle

/etc/systemd/system/backup.timer

[Unit]

Description=Daily backup timer

[Timer]

OnCalendar=daily

Persistent=true

RandomizedDelaySec=10min

[Install]

WantedBy=timers.target

有効化。

sudo systemctl daemon-reload

sudo systemctl enable --now backup.timer

sudo systemctl list-timers

systemd timers が cron に勝る点。

1. **ジャーナルロギング統合**: `journalctl -u backup.service` 一発で実行ログを確認。cron はメールか syslog。

2. **Persistent**: ホストが落ちて欠落した実行を、立ち上がった直後に 1 回だけ実行。anacron 相当が組み込み。

3. **RandomizedDelaySec**: 同じ時刻に全ホストが一斉に cron を走らせて負荷が跳ねる問題を自動で分散。

4. **OnCalendar の表現力**: `Mon..Fri 09:00`、`*-*-1..7 09:00`(毎月第 1 週の平日)、`quarterly`、`yearly` など人間に読める形式。

5. **リソース制限**: Service unit が `CPUQuota`、`MemoryMax`、`IOSchedulingClass` といった cgroup 制限を直接持つ。

6. **依存関係**: `Requires=`、`After=` で「別サービスが起きているときだけ実行」のような条件を表現できる。

OnCalendar の例。

毎日 03:00

OnCalendar=daily

毎週日曜 04:00

OnCalendar=Sun 04:00

毎月 1 日と 15 日

OnCalendar=*-*-01,15 02:00

平日 10 分おき

OnCalendar=Mon..Fri *:0/10

6 時間おき (0, 6, 12, 18)

OnCalendar=*-*-* 0/6:00:00

`systemd-analyze calendar 'Mon..Fri *:0/10'` で表記を検証できる。次の発火時刻も出力される。

cron から systemd timer への移行は、2026 年の標準推奨と言ってよい。Ubuntu 24.04 LTS と RHEL 10 のいずれも cron はオプションパッケージで、systemd timer が標準メカニズムになっている。

4. Vercel Cron — サーバーレススケジュール

Vercel Cron は 2022 年に GA となり、2026 年現在は Next.js・SvelteKit などのフレームワークと統合された標準スケジューラだ。

設定は `vercel.json` 1 ファイル。

{

"crons": [

{

"path": "/api/cron/daily-report",

"schedule": "0 9 * * *"

},

{

"path": "/api/cron/cleanup",

"schedule": "*/15 * * * *"

}

]

}

ハンドラ(Next.js App Router)。

// app/api/cron/daily-report/route.ts

export async function GET(request: Request) {

// Vercel は Authorization ヘッダで自前のシークレットを送る

const authHeader = request.headers.get('authorization')

if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {

return new NextResponse('Unauthorized', { status: 401 })

}

// 実処理

await sendDailyReport()

return NextResponse.json({ ok: true })

}

Vercel Cron の特徴。

- **Hobby/Free プラン**: 1 日 cron 最大 2 個、毎分 1 回。学習・個人プロジェクト向け。

- **Pro プラン**: 40 個の cron、毎分複数回可。実運用に耐える。

- **Enterprise**: 事実上無制限。

- **タイムアウト**: 関数自体のタイムアウト(Pro 60 秒、Enterprise 900 秒)内に終える必要あり。

- **HMAC 認証**: `CRON_SECRET` 環境変数で外部からの任意呼び出しを防止。

- **監視**: Vercel ダッシュボードで最後の実行とステータスを確認。

制約は明確だ。関数タイムアウト内に終わるものに限られるため、**長時間処理**(バッチ、大量データ処理)には不向き。長くなるなら **ジョブキュー**(Inngest、Trigger.dev、QStash)に投げて即座に終わるパターンが定番。Vercel Cron 自体は「適時に起こすアラーム」だ。

5. AWS EventBridge Scheduler(2022 年 11 月) — CloudWatch Events Rules の置き換え

AWS の cron は 2022 年 11 月に **EventBridge Scheduler** に世代交代した。以前の標準は **CloudWatch Events Rules**(CloudWatch Events rate / cron expression)だったが、EventBridge Scheduler は 1 アカウントあたり 1 億スケジュールまで扱えると発表されてからは推奨オプションとなった。

差分の核心。

| 項目 | CloudWatch Events Rules(旧) | EventBridge Scheduler(新) |

| --- | --- | --- |

| 提供開始 | 2016 | 2022 年 11 月 |

| スケジュール数上限 | アカウントあたり 100~300(サービスクォータ) | アカウントあたり 1 億 |

| 一回限りスケジュール | なし | `at(...)` 表現対応 |

| タイムゾーン | UTC 固定 | IANA TZ 指定可 |

| フレキシブル時間ウィンドウ | なし | FlexibleTimeWindowMinutes |

| ターゲット統合 | EventBus 経由の間接 | Lambda、SQS、ECS、SageMaker、Step Functions など 200+ に直接 |

| 推奨 | 非推奨ガイダンス | AWS 公式推奨 |

EventBridge Scheduler を作る(Terraform)。

resource "aws_scheduler_schedule" "daily_report" {

name = "daily-report"

group_name = "default"

flexible_time_window {

mode = "OFF"

}

schedule_expression = "cron(0 9 ? * MON-FRI *)"

schedule_expression_timezone = "Asia/Tokyo"

target {

arn = aws_lambda_function.report.arn

role_arn = aws_iam_role.scheduler.arn

retry_policy {

maximum_retry_attempts = 3

maximum_event_age_in_seconds = 3600

}

}

}

AWS の cron 表記は 6 フィールド(分 時 日 月 曜日 年)で、`?` は「気にしない」を意味する。POSIX cron と微妙に異なるので要注意。

もうひとつの選択肢が **Step Functions の Wait + EventBridge** の組み合わせだ。ワークフロー内の「5 分待ってから次へ」のようなパターンは Step Functions 自身の Wait state で表現し、外部から起こすところを EventBridge Scheduler が担う。

2026 年の推奨は **新規プロジェクトは EventBridge Scheduler**、既存の CloudWatch Events Rules は段階的に移行。AWS 自身がコンソールでマイグレーションツールを提供している。

6. Cloudflare Workers Cron Triggers

Cloudflare Workers はエッジ関数プラットフォームで、**Cron Triggers** という名前で cron 表記ベースのスケジューリングを提供する。2026 年現在、Workers の無料プランでも cron を 3 つまで持てる。

`wrangler.toml` の設定。

name = "my-worker"

main = "src/index.ts"

compatibility_date = "2026-05-01"

[triggers]

crons = [

"0 */6 * * *",

"0 0 * * 0"

]

ハンドラ。

// src/index.ts

export default {

async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext) {

console.log(`cron fired: ${event.cron} at ${event.scheduledTime}`)

// 実処理

await runCleanup(env)

},

async fetch(req: Request): Promise<Response> {

return new Response('Worker alive')

}

}

Cloudflare の差別化ポイント。

- **エッジ全球実行**: cron がどこで起きるかは Cloudflare が決める(ルーティング最適化)。ワークロードにタイムゾーン依存があるならコード側で処理する。

- **無料枠込み**: 10 万リクエスト / 日の中に cron も含まれる。

- **30 秒 CPU 上限**: 標準 Worker は 30 秒 CPU。長時間処理は Durable Objects か Queues と組み合わせる。

- **イベントメタデータ**: `event.cron` でどの式が発火したかが分かるので、1 関数で複数スケジュールを分岐できる。

Workers Cron Triggers は Vercel Cron と似ているが、**エッジ分散** と **手厚い無料枠** が強みだ。

7. GitHub Actions schedule / GitLab schedule pipelines

CI/CD プラットフォーム自体が cron になるパターンは 2020 年以降に爆発的に増えた。インフラ運用、データ同期、定期点検などを **ワークフローファイル** で管理できる。

GitHub Actions schedule の例。

.github/workflows/nightly.yml

name: Nightly Maintenance

on:

schedule:

- cron: '0 17 * * *' # UTC 17:00 = JST 02:00

workflow_dispatch: # 手動実行も許可

jobs:

cleanup:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- name: Run cleanup

run: ./scripts/cleanup.sh

GitHub Actions schedule の注意点。

1. **UTC 固定**: タイムゾーンオプションなし。自前で変換する必要がある。

2. **低活動リポジトリの自動停止**: 60 日 push がないと、schedule ワークフローは自動的に無効化される。あえてコミットする必要あり。

3. **遅延あり**: GitHub の負荷次第で、約束時刻から数分~数十分遅れて発火することはよくある。

4. **無料枠**: パブリックリポジトリは無料、プライベートは分単位の quota から消費。

GitLab schedule pipelines。

.gitlab-ci.yml

nightly:

script:

- ./scripts/cleanup.sh

rules:

- if: $CI_PIPELINE_SOURCE == "schedule"

GitLab はコード以外に、**CI/CD > Schedules** の UI から時刻・タイムゾーン・変数を設定する。GitHub Actions と違ってタイムゾーン設定が効くのが強み。

CI スケジュールが向いているケース。

- 依存関係のセキュリティスキャン / SBOM 更新。

- 静的サイトの再生成(為替・天気など)。

- 毎日 / 毎週のレポートメール送信。

- Git リポジトリのミラーリング。

不向きなケース。

- 分単位の精度が必要な処理(CI は約束時刻より遅れがち)。

- リアルタイムなインフラ操作(EventBridge Scheduler か Vercel Cron 推奨)。

8. Kubernetes CronJobs — kind: CronJob

Kubernetes には 1.21 で CronJob が安定化した。一度きりのコンテナ実行リソースである Job の上に cron 表記を載せたもの。

apiVersion: batch/v1

kind: CronJob

metadata:

name: daily-cleanup

spec:

schedule: "0 2 * * *"

timeZone: "Asia/Tokyo"

concurrencyPolicy: Forbid

startingDeadlineSeconds: 600

successfulJobsHistoryLimit: 3

failedJobsHistoryLimit: 1

jobTemplate:

spec:

backoffLimit: 2

template:

spec:

restartPolicy: OnFailure

containers:

- name: cleanup

image: registry.example.com/cleanup:1.4.2

command: ["/app/cleanup.sh"]

resources:

requests: { cpu: "100m", memory: "128Mi" }

limits: { cpu: "1", memory: "512Mi" }

Kubernetes CronJob の主なフィールド。

- **schedule**: 5 フィールドの cron 表現。

- **timeZone**: 1.25 から正式。IANA TZ(例: `Asia/Tokyo`)。

- **concurrencyPolicy**: `Allow`(既定) / `Forbid`(前のジョブが終わっていなければ起動しない) / `Replace`(新しいジョブが前のジョブを殺す)。

- **startingDeadlineSeconds**: この秒数以内に起こせなければ諦める(コントローラが少し遅れたとき向け)。

- **successfulJobsHistoryLimit / failedJobsHistoryLimit**: Job オブジェクトを何件残すか。

- **backoffLimit**: Pod 失敗時の再試行回数。

CronJob の落とし穴。

1. **clock drift**: ノード間で時刻がずれると発火時刻が揺れる。NTP は必須。

2. **コントローラ遅延**: kube-controller-manager に負荷がかかると発火が遅れる。平均で 1 秒〜数十秒。

3. **タイムアウト未設定**: Job に `activeDeadlineSeconds` を入れないと無限実行が起こり得る。

4. **タイムゾーン罠**: 1.25 以前のクラスタは常に UTC。DST をまたぐ時刻で 2 回または 0 回発火する古典的バグがある。

運用 Tips。

- CronJob ごとに **PodDisruptionBudget** と **PriorityClass** を定義してノード障害に強くする。

- ロギング: stdout/stderr をコンテナログ → Loki / OpenSearch へ収集。

- 監視: Prometheus の `kube_cronjob_*` メトリクス + Alertmanager で「最後に成功してから X 時間経過したらアラート」。

9. BullMQ(Node) / Sidekiq(Ruby) / Celery Beat(Python)

アプリ内のバックグラウンドジョブ + 定期作業のパターンは、**Redis ベースのジョブキュー + スケジューラ** が定番だ。2026 年の三大選択肢。

BullMQ — Node.js

BullMQ は OptimalBits の Bull の後継で、2026 年の Node.js 界の標準キュー。

const connection = { host: '127.0.0.1', port: 6379 }

// キュー

const reportsQueue = new Queue('reports', { connection })

// 反復ジョブ(cron)登録

await reportsQueue.add(

'daily-report',

{ type: 'pdf' },

{

repeat: { pattern: '0 9 * * 1-5', tz: 'Asia/Tokyo' },

jobId: 'daily-report',

}

)

// ワーカー

new Worker('reports', async (job) => {

console.log(`processing ${job.name}`)

await generateReport(job.data)

}, { connection })

BullMQ の強み。

- **TypeScript first**: 型安全。

- **Repeatable jobs**: cron か every(ミリ秒)。tz 指定可。

- **Flow producer**: 親子ジョブの依存関係(ワークフロー風)。

- **Rate limiting / priority / retries**: 1 行で。

**BullMQ Pro** は有料。グループ、一時停止、優先キューグループなどエンタープライズ機能を追加。BullMQ を運用する会社(Taskforce.sh)がメンテナで、無料 OSS も活発。

Sidekiq — Ruby

Sidekiq は Ruby 界で圧倒的 1 位。2012 年に Mike Perham が開始、2026 年も活発に開発が続いている。

Gemfile

gem 'sidekiq'

gem 'sidekiq-scheduler' # または sidekiq-cron

config/sidekiq.yml

:schedule:

daily_report:

cron: '0 9 * * 1-5'

class: DailyReportJob

queue: reports

app/jobs/daily_report_job.rb

class DailyReportJob

include Sidekiq::Job

sidekiq_options queue: :reports, retry: 3

def perform

ReportMailer.daily.deliver_now

end

end

Sidekiq の派生。

- **Sidekiq(OSS)**: 無料。Redis。Web UI 標準。

- **Sidekiq Pro**: 有料。信頼性強化(reliable fetch、batches)。

- **Sidekiq Enterprise**: さらに高価。ユニークジョブ、定期ジョブ内蔵(別 gem 不要)、マルチプロセス、マルチ DC。

Mike Perham のビジネスモデルは、OSS と有料版を単一メンテナが運営する好例としてよく引用される。

Celery Beat — Python

Celery は Python のバックグラウンドキューの標準。**Celery Beat** がそのスケジューラコンポーネント。

celery_app.py

from celery import Celery

from celery.schedules import crontab

app = Celery('myapp', broker='redis://localhost:6379/0')

app.conf.beat_schedule = {

'daily-report': {

'task': 'tasks.generate_report',

'schedule': crontab(hour=9, minute=0, day_of_week='1-5'),

},

'every-15-min-cleanup': {

'task': 'tasks.cleanup',

'schedule': 900.0, # 秒単位

},

}

app.conf.timezone = 'Asia/Tokyo'

tasks.py

@app.task

def generate_report():

...

実行。

ワーカー

celery -A celery_app worker -l info

Beat スケジューラ(単一インスタンスのみ)

celery -A celery_app beat -l info

Celery Beat の落とし穴 — **Beat は単一ノード** だけにすること。2 つのノードで立ち上げると、すべてのジョブがキューに 2 回入る。分散ロックが欲しければ `celery-redbeat` というバックエンドを使う(Redis 分散ロックで Beat が 2 つ生きていてもキューに 1 回しか入らない)。

10. RQ / dramatiq / APScheduler — Python の選択肢

Celery 以外にも、Python にはより軽い代替がいくつかある。

RQ(Redis Queue)

最もシンプルな Python ジョブキュー。Celery より圧倒的に簡単だが、その分機能も少ない。

from rq import Queue

from rq_scheduler import Scheduler

from redis import Redis

from datetime import datetime

scheduler = Scheduler(connection=Redis())

scheduler.cron(

'0 9 * * 1-5',

func=generate_report,

queue_name='reports',

)

`rq-scheduler` パッケージが cron 表記をサポート。RQ が向く場面: 単一ホスト、単一ワーカー、軽量なバックグラウンド処理。

dramatiq

RQ より頑健、Celery より単純な中間。RabbitMQ 推奨だが Redis も使える。

from dramatiq.brokers.rabbitmq import RabbitmqBroker

from dramatiq_crontab import cron

dramatiq.set_broker(RabbitmqBroker())

@cron('0 9 * * 1-5')

@dramatiq.actor

def daily_report():

...

dramatiq の強み: リトライバックオフ、デッドレター、ミドルウェアシステムが綺麗。Celery が重すぎ、RQ が軽すぎると感じるチームの選択肢。

APScheduler

ワーカーが別途要らない **アプリ内インプロセススケジューラ**。Flask・FastAPI から直接呼ぶ。

from apscheduler.schedulers.asyncio import AsyncIOScheduler

from apscheduler.triggers.cron import CronTrigger

scheduler = AsyncIOScheduler(timezone='Asia/Tokyo')

scheduler.add_job(

daily_report,

CronTrigger.from_crontab('0 9 * * 1-5')

)

scheduler.start()

APScheduler が向く場面: 1〜2 プロセスの小規模アプリで、外部 Redis/RabbitMQ を置きたくない場合。限界: 分散ロックが弱い、プロセスが死ぬと欠落。SQLAlchemy / MongoDB / Redis のジョブストアがあるが、いずれも強整合性ではない。

選択ガイド。

| ツール | バックエンド | 分散 | 複雑度 | 適合 |

| --- | --- | --- | --- | --- |

| Celery + Beat | Redis / RabbitMQ | Yes(Beat は 1 個のみ) | 高 | 大規模アプリ、多様なワークロード |

| RQ + rq-scheduler | Redis | 中 | 低 | 単一ホスト、軽量ジョブ |

| dramatiq | RabbitMQ / Redis | Yes | 中 | 信頼性 + 単純さ |

| APScheduler | インプロセス | No | 非常に低 | 1〜2 プロセスの小アプリ |

11. Airflow / Dagster / Prefect / Temporal / Inngest / Trigger.dev — ワークフロー

ワークフローエンジンは cron の自然な進化形。**多段階** + **リトライ** + **状態追跡** + **可視化** が中心。このカテゴリは別記事で深掘りしたので、ここでは cron 視点に絞って整理する。

Apache Airflow

データエンジニアリングの標準。DAG(Directed Acyclic Graph)の中に schedule_interval を置く。

from airflow import DAG

from airflow.operators.python import PythonOperator

from datetime import datetime

with DAG(

'daily_etl',

schedule_interval='0 2 * * *',

start_date=datetime(2026, 1, 1),

catchup=False,

tags=['etl'],

) as dag:

extract = PythonOperator(task_id='extract', python_callable=do_extract)

transform = PythonOperator(task_id='transform', python_callable=do_transform)

load = PythonOperator(task_id='load', python_callable=do_load)

extract >> transform >> load

Airflow の強みは可視化と catchup(欠落時刻のバックフィル)。弱みは運用の複雑さと重いスケジューラ。

Dagster

アセットベースのモデル。cron だけでなく、**データアセットが古くなったとき** に発火させるパターンが強力。

from dagster import asset, ScheduleDefinition, define_asset_job

@asset

def daily_metrics():

...

daily_job = define_asset_job('daily_metrics_job', selection=[daily_metrics])

daily_schedule = ScheduleDefinition(

job=daily_job,

cron_schedule='0 2 * * *',

execution_timezone='Asia/Tokyo',

)

Prefect

Python の関数デコレータでワークフローを定義。cron 以外に interval、rrule(反復)も対応。

from prefect import flow, task

from prefect.deployments import Deployment

from prefect.client.schemas.schedules import CronSchedule

@task

def fetch(): ...

@flow

def daily_pipeline():

fetch()

Deployment.build_from_flow(

flow=daily_pipeline,

name='daily',

schedule=CronSchedule(cron='0 2 * * *', timezone='Asia/Tokyo'),

).apply()

Temporal Schedules

Temporal はワークフローエンジン界の新星。2023 年に Schedules API が正式に出て、cron + ワークフローの信頼性を統合した。

const client = new Client()

await client.schedule.create({

scheduleId: 'daily-report',

spec: {

cronExpressions: ['0 9 * * 1-5'],

timezoneName: 'Asia/Tokyo',

},

action: {

type: 'startWorkflow',

workflowType: 'DailyReportWorkflow',

workflowId: 'daily-report',

taskQueue: 'reports',

},

policies: {

overlap: 'SKIP', // 前のワークフローが終わっていなければスキップ

catchupWindow: '1h',

},

})

Temporal Schedules の強みは **ワークフロー自体が永続的** であること。cron が発火してワークフローが始まれば、そのワークフローはホストが死んでも別のホストで継続実行される。本物の「fire and forget」。

Inngest Crons

サーバーレス関数 / イベント駆動ワークフロー。cron 表記のほかイベント駆動トリガーも持つ。

export const dailyReport = inngest.createFunction(

{ id: 'daily-report' },

{ cron: 'TZ=Asia/Tokyo 0 9 * * 1-5' },

async ({ step }) => {

const data = await step.run('fetch', fetchData)

await step.run('send', () => sendReport(data))

}

)

Trigger.dev v3

React 風のワークフローコード。cron 以外に `cron.list`、`schedules.create()` のような動的スケジュール API も提供。

export const dailyReport = schedules.task({

id: 'daily-report',

cron: { pattern: '0 9 * * 1-5', timezone: 'Asia/Tokyo' },

run: async (payload) => {

// payload.timestamp で発火時刻を受け取る

}

})

12. Hatchet — 新星ワークフロー

Hatchet は 2024 年に登場したワークフローエンジン。PostgreSQL 上にジョブキュー + ワークフロー + スケジュールを統合したのが特徴。

const hatchet = Hatchet.init()

hatchet.workflow({

id: 'daily-report',

on: { cron: '0 9 * * 1-5' },

steps: [

{

name: 'fetch-data',

run: async (ctx) => fetchData(),

},

{

name: 'send-email',

parents: ['fetch-data'],

run: async (ctx) => {

const data = ctx.stepOutput('fetch-data')

await sendEmail(data)

},

}

]

})

Hatchet の差別化ポイント。

- **PostgreSQL 単一依存**: Redis・Kafka・NATS のような別依存は不要。Postgres 1 インスタンスでキュー + ジョブ保存 + ワークフロー状態のすべて。

- **セルフホスト向き**: 単一 Docker イメージでフルスタックを動かせる。

- **OpenTelemetry 内蔵**: すべてのジョブ / ワークフローがトレースとして出る。

- **有料 / 無料**: OSS は無料、Hatchet Cloud がマネージド版。

2026 年で Hatchet が向くのは: PostgreSQL を既に運用している小〜中規模チームが Temporal より軽い選択肢を探すとき。

13. Quartz(Java) / Spring @Scheduled / Hangfire(.NET)

JVM と .NET 界の cron。

Quartz Scheduler

JVM 界の古典的スケジューリングライブラリ。1999 年からあり、2026 年も活発。

public class DailyReportJob implements Job {

public void execute(JobExecutionContext ctx) {

// 処理

}

}

JobDetail job = newJob(DailyReportJob.class)

.withIdentity("dailyReport", "reports")

.build();

CronTrigger trigger = (CronTrigger) newTrigger()

.withIdentity("dailyReportTrigger", "reports")

.withSchedule(cronSchedule("0 0 9 ? * MON-FRI").inTimeZone(TimeZone.getTimeZone("Asia/Tokyo")))

.build();

scheduler.scheduleJob(job, trigger);

Quartz は **JDBC JobStore** でジョブ状態を RDB に永続化し、クラスタモード(複数のスケジューラインスタンスが同じ DB を共有)にも対応。AWS EventBridge や BullMQ のようなマネージドより精緻な制御が必要なときに。

Spring @Scheduled

Spring Boot ならアノテーション 1 つで cron ジョブを作れる。

@Component

public class ScheduledTasks {

@Scheduled(cron = "0 0 9 * * MON-FRI", zone = "Asia/Tokyo")

public void dailyReport() {

// 処理

}

@Scheduled(fixedRate = 60000)

public void healthcheck() {

// 60 秒おき

}

}

main クラスに `@EnableScheduling` を付ければ有効になる。Spring の cron 表記は **6 フィールド(秒 分 時 日 月 曜日)** に注意。POSIX cron とは違う。

分散環境では `ShedLock` ライブラリで分散ロックを足し、複数インスタンスで同じジョブが 2 回回らないようにする。

Hangfire — .NET

.NET 界のバックグラウンドジョブ + スケジュールライブラリ。

// Startup.cs

services.AddHangfire(c => c.UseSqlServerStorage(connStr));

services.AddHangfireServer();

// Program / Controller

RecurringJob.AddOrUpdate<IDailyReportService>(

"daily-report",

svc => svc.SendReport(),

"0 9 * * 1-5",

TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time")

);

Hangfire の強み。

- **SQL Server / PostgreSQL / Redis** バックエンドが選べる。

- **ダッシュボード**: ジョブ状態、失敗、リトライをブラウザで確認。

- **自動リトライ**: 失敗時の指数バックオフ。

- **OSS 無料 + Hangfire Pro 有料**。

Hangfire は .NET 界の事実上の標準だ。

`Castle Windsor` のような IoC コンテナとの統合も綺麗で、依存性注入が整理しやすい。

14. fcron / anacron — Linux の代替

cron の代替が 2 つ、Linux 界には残っている。

anacron

ホストが常時起動とは限らない環境(ノート PC、デスクトップ)向けの cron 補完。ジョブの予定時刻にホストが落ちていれば、次に起きたときに 1 回だけ実行してくれる。

/etc/anacrontab

period delay job-identifier command

1 5 cron.daily run-parts /etc/cron.daily

7 25 cron.weekly run-parts /etc/cron.weekly

@monthly 45 cron.monthly run-parts /etc/cron.monthly

`period` は日数、`delay` は起動後の待機分数、`job-identifier` は最終実行を追跡する名前。systemd timers の `Persistent=true` が同じ機能をより綺麗にこなす。

fcron

cron と anacron の統合を目指したもの。1999 年から開発されており、「多様な環境を 1 ツールで」が目標。

fcrontab の例

@daily,mailto=ops backup.sh

@reboot,nice=10 startup-checks.sh

%every 10 minutes after boot * * * * /usr/local/bin/poll.sh

fcron の差別化ポイント。

- `@daily`、`%hours`、`%mins` など人間に読みやすい独自表記。

- 起動後 N 分のような相対時刻指定。

- 落ちていた間のジョブの追いつき。

- ジョブの同時実行制限のようなリソース管理。

2026 年現在、fcron はニッチなツール。systemd timers が実質同じ機能を提供しつつ、より深いシステム統合を持つから。それでも一部の Debian / Gentoo 環境ではまだ使われている。

15. Healthchecks.io / Cronitor.io — 監視

cron の「黙って失敗する」問題を解くデッドマンスイッチサービス。ジョブが「完了した」と ping を送らねばならず、送らないとアラート。別記事でより深く触れているので、ここでは使用パターンに絞る。

Healthchecks.io

OSS + マネージド。無料プランが手厚い(チェック 20 個まで)。

crontab

0 9 * * 1-5 /usr/local/bin/report.sh && curl -fsS --retry 3 https://hc-ping.com/PROJECT_ID/daily-report > /dev/null

または開始 / 終了 / 失敗の 3 つに ping を分ける。

#!/bin/bash

URL="https://hc-ping.com/PROJECT_ID/daily-report"

curl -fsS --retry 3 "$URL/start"

if /usr/local/bin/report.sh; then

curl -fsS --retry 3 "$URL"

else

curl -fsS --retry 3 "$URL/fail"

fi

`/start` と終了 ping の間の時間で実行時間を測る。`/fail` で失敗アラート。Slack・メール・PagerDuty 統合あり。

Cronitor.io

商用 SaaS。より精緻なメトリクス、アラートルーティング。Healthchecks.io のマネージド競合。

Cronitor も同じパターン

0 9 * * 1-5 cronitor exec daily-report /usr/local/bin/report.sh

`cronitor` CLI が開始 / 終了 / 失敗 ping を自動で送る。

運用推奨: **重要な cron すべてに監視を仕掛ける**。2026 年の SRE 合意は「ping のない cron は運用負債」。

16. Nomad periodic jobs

HashiCorp Nomad の cron 相当。コンテナ / バイナリ / Java / Docker / QEMU など多様なワークロードタイプに対応するのが差別化。

job "daily-cleanup" {

type = "batch"

periodic {

cron = "0 2 * * *"

time_zone = "Asia/Tokyo"

prohibit_overlap = true

}

group "cleanup" {

task "run" {

driver = "docker"

config {

image = "registry.example.com/cleanup:1.4.2"

command = "/app/cleanup.sh"

}

resources {

cpu = 500

memory = 256

}

}

}

}

Nomad の強み。

- **単一バイナリ**: HashiCorp 標準の運用モデル。

- **多様な driver**: Docker だけでなく raw_exec、java、qemu、podman など。

- **Consul / Vault 統合**: サービスディスカバリとシークレット。

- **k8s より単純**: 小規模チームでも運用しやすい。

Kubernetes CronJob と比べると、Nomad は **小〜中規模環境** に向く。大規模 SaaS は k8s が優勢。

17. 韓国 / 日本 — トス、カカオ、メルカリ

トス — cron インフラ

トスは SLASH カンファレンスで「分散 cron インフラ」のセッションを何度か出している。要点。

- **自前 ScheduleJob プラットフォーム**: トス内部の cron マネージャ。数千個の cron ジョブを中央管理。

- **分散ロック**: 同一ジョブが 2 ホストで走らないように Redis または ZooKeeper の分散ロック。

- **k8s CronJob の上の抽象化レイヤ**: 開発者は YAML ではなく UI で登録。

- **監視自動化**: ジョブ登録時に自動でデッドマンスイッチまで作る。

- **タイムゾーン統合**: すべてのジョブが KST。UTC 変換はプラットフォームが担当。

トスの核心: 「cron ジョブが数百を超えたら、ツールではなく **プラットフォーム** が要る」。

カカオ — タスクスケジューリング

カカオは if(kakao) カンファレンスでタスクスケジューリングのインフラを共有している。

- **カカオトークプッシュ**: 定時送信プッシュは独立スケジューラ。Quartz の上に自前で構築。

- **データパイプライン**: Airflow + 自前ラッパー。

- **広告精算**: Sidekiq 風のジョブキュー + cron の組み合わせ。

カカオの教訓: 「1 つのツールではすべてをカバーできない。ワークロードごとに最も適したツールをモザイクのように組み合わせる」が現実解。

メルカリ — Scheduled Jobs

メルカリ日本は Microservices 運用の代表例として有名。

- **Google Cloud Tasks + Cloud Scheduler**: GCP 中心のインフラ。

- **k8s CronJob**: インフラ整理タスク。

- **各マイクロサービス内のインプロセススケジュール**: 軽量なジョブはサービス自身が処理。

メルカリのエンジニアリングブログ(英語)が定期的に運用事例を公開している。

18. 誰が何を選ぶべきか — シンプル / 分散 / バックグラウンド / 信頼性

2026 年の cron 選定をデシジョンツリーにまとめると。

ジョブは 1 ホスト・1 コマンドで完結?

├── YES → systemd timers(cron ではなく)

│ + Healthchecks.io ping

└── NO →

インフラはサーバーレス?

├── Vercel ベース → Vercel Cron

├── AWS ベース → EventBridge Scheduler

├── Cloudflare → Workers Cron Triggers

└── コンテナ → k8s CronJob または Nomad periodic

ジョブはアプリ内バックグラウンドの一部?

├── Node → BullMQ

├── Ruby → Sidekiq

├── Python → Celery Beat(大)/ RQ(小)/ dramatiq(中)

├── Java → Quartz / Spring @Scheduled

└── .NET → Hangfire

ジョブは多段階ワークフロー?

├── データ → Airflow / Dagster / Prefect

├── 信頼性 → Temporal

├── サーバーレス → Inngest / Trigger.dev v3

└── Postgres のみ → Hatchet

CI 活動に紐づく?

└── GitHub Actions schedule / GitLab schedule pipelines

**ルール化**。

1. **単純なジョブ + 1 ホスト** → systemd timers。

2. **クラウドマネージド** → Vercel / EventBridge / Cloudflare のうちインフラ依存に合うもの。

3. **アプリ統合** → 言語別の標準(BullMQ / Sidekiq / Celery Beat / Quartz / Hangfire)。

4. **ワークフロー信頼性** → Temporal / Hatchet。

5. **データパイプライン** → Airflow / Dagster / Prefect。

6. **何を使っても** → Healthchecks.io か Cronitor.io で監視。

2026 年の cron 運用は「1 ツールですべて」ではなく、**「ワークロードごとに最適なツールを選び、すべてに監視を付ける」** が標準だ。

参考 / References

- [cron(8) — Unix manual page](https://man7.org/linux/man-pages/man8/cron.8.html)

- [crontab(5) — format specification](https://man7.org/linux/man-pages/man5/crontab.5.html)

- [systemd.timer documentation](https://www.freedesktop.org/software/systemd/man/systemd.timer.html)

- [systemd-analyze calendar](https://www.freedesktop.org/software/systemd/man/systemd-analyze.html)

- [Vercel Cron Jobs](https://vercel.com/docs/cron-jobs)

- [AWS EventBridge Scheduler announcement (Nov 2022)](https://aws.amazon.com/blogs/compute/introducing-amazon-eventbridge-scheduler/)

- [AWS EventBridge Scheduler documentation](https://docs.aws.amazon.com/scheduler/latest/UserGuide/what-is-scheduler.html)

- [Cloudflare Workers Cron Triggers](https://developers.cloudflare.com/workers/configuration/cron-triggers/)

- [GitHub Actions schedule events](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule)

- [GitLab Pipeline schedules](https://docs.gitlab.com/ee/ci/pipelines/schedules.html)

- [Kubernetes CronJob](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/)

- [BullMQ documentation](https://docs.bullmq.io/)

- [BullMQ Pro](https://bullmq.io/pro/)

- [Sidekiq documentation](https://github.com/sidekiq/sidekiq/wiki)

- [Sidekiq Pro / Enterprise](https://sidekiq.org/products/pro.html)

- [Celery documentation](https://docs.celeryq.dev/)

- [Celery Beat periodic tasks](https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html)

- [RQ — Redis Queue](https://python-rq.org/)

- [dramatiq documentation](https://dramatiq.io/)

- [APScheduler documentation](https://apscheduler.readthedocs.io/)

- [Apache Airflow](https://airflow.apache.org/)

- [Dagster schedules](https://docs.dagster.io/concepts/automation/schedules)

- [Prefect schedules](https://docs.prefect.io/v3/automate/add-schedules)

- [Temporal Schedules](https://docs.temporal.io/develop/typescript/schedules)

- [Inngest crons](https://www.inngest.com/docs/functions/triggers#cron)

- [Trigger.dev v3 Scheduled tasks](https://trigger.dev/docs/tasks/scheduled)

- [Hatchet documentation](https://docs.hatchet.run/)

- [Quartz Scheduler](https://www.quartz-scheduler.org/)

- [Spring @Scheduled](https://docs.spring.io/spring-framework/reference/integration/scheduling.html)

- [Hangfire documentation](https://docs.hangfire.io/)

- [fcron homepage](https://fcron.free.fr/)

- [anacron documentation](https://man7.org/linux/man-pages/man8/anacron.8.html)

- [Healthchecks.io](https://healthchecks.io/)

- [Cronitor](https://cronitor.io/)

- [HashiCorp Nomad periodic jobs](https://developer.hashicorp.com/nomad/docs/job-specification/periodic)

- [Toss SLASH](https://toss.tech/slash)

- [Kakao if(kakao) conference](https://if.kakao.com/)

- [Mercari Engineering](https://engineering.mercari.com/en/blog/)

현재 단락 (1/656)

2026 年のあるチームの設計レビュー。

작성 글자: 0원문 글자: 25,225작성 단락: 0/656