필사 모드: Cron とスケジュールタスク 2026 — systemd timers / Vercel Cron / AWS EventBridge Scheduler / k8s CronJobs / BullMQ / Sidekiq / Temporal 徹底ガイド
日本語プロローグ — 「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 年のあるチームの設計レビュー。