Crontab チートシート:50+ Cron 表現、構文、現代スケジューラのガイド
cron 表現は 5 つのフィールド——分、時、日、月、曜日——にコマンドを続けた書式である。同じ文法を 1979 年から Unix のスケジューリングが使い、Kubernetes CronJob、GitHub Actions、AWS EventBridge、Vercel cron トリガーも採用している。一度覚えれば他のスケジューラでも使い回せる。
このページは、Linux のタスク、Kubernetes の CronJob、GitHub Actions のトリガー、あるいは「5 分おきのジョブがなぜ 1 時間に 1 回しか発火しないのか」のデバッグで、すぐ表現が必要な開発者向けである。コピペ用の表現が欲しければ「クイックリファレンス表」へ、フィールドの規則を知りたければ「構文の分解」へ進む。表現をその場で検証したい場合は Crontab ジェネレーター — cron 式の生成・パース・検証 —— ブラウザで動くプライバシーファーストの crontab guru の代替 —— を開けばよい。
Cron 表現クイックリファレンス表
よく使う 30 個の表現。すべて POSIX 標準の 5 フィールド cron として有効で、crontab -e、Kubernetes の schedule:、GitHub Actions の cron: にそのまま貼り付けられる。
| スケジュール | Cron 表現 | 平易な説明 |
|---|---|---|
| 毎分 | * * * * * | 毎日、終日、毎分 |
| 5 分ごと | */5 * * * * | 分 0, 5, 10, …, 55 |
| 15 分ごと | */15 * * * * | 分 0, 15, 30, 45 |
| 30 分ごと | */30 * * * * | 分 0 と 30 |
| 1 時間ごと | 0 * * * * | 毎時 00 分 |
| 2 時間ごと | 0 */2 * * * | 時 0, 2, 4, …, 22 |
| 6 時間ごと | 0 */6 * * * | 時 0, 6, 12, 18 |
| 1 日 2 回(9 時と 21 時) | 0 9,21 * * * | 9 時と 21 時の 0 分 |
| 平日 9 時 | 0 9 * * 1-5 | 月〜金 09:00 |
| 週末 9 時 | 0 9 * * 0,6 | 土日 09:00 |
| 毎日深夜 0 時 | 0 0 * * * | 毎日 00:00 |
| 毎日 02:30 | 30 2 * * * | トラフィックの少ないバッチ時間帯 |
| 毎週月曜 9 時 | 0 9 * * 1 | 月曜 09:00 |
| 毎週金曜 17 時 | 0 17 * * 5 | 金曜 17:00 |
| 毎週日曜深夜 0 時 | 0 0 * * 0 | @weekly と等価 |
| 毎月 1 日 0 時 | 0 0 1 * * | 1 日 00:00——@monthly と等価 |
| 毎月 15 日正午 | 0 12 15 * * | 月中の給与処理時間帯 |
| 月末判定(ラッパー) | 0 0 28-31 * * + スクリプト | 日付チェックが必要 |
| 四半期(1/4/7/10 月 1 日) | 0 0 1 JAN,APR,JUL,OCT * | 各四半期の初日 |
| 年 1 回(1 月 1 日) | 0 0 1 1 * または @yearly | 元日深夜 0 時 |
| 平日 9-17 時の 5 分ごと | */5 9-17 * * 1-5 | 営業時間ポーリング |
| 週末の 30 分ごと | */30 * * * 0,6 | 土日の監視 |
| 毎時 2 回、15 分と 45 分 | 15,45 * * * * | :00 集中を避ける |
| 第 1 月曜(ラッパー) | 0 9 1-7 * 1 + AND チェック | ラッパーが必要(後述) |
| マクロ | @hourly @daily @weekly @monthly @yearly | 非標準だが広く対応 |
| 起動時のみ | @reboot | 非標準、vixie cron 限定 |
いずれの表現も Crontab ジェネレーター — cron 式の生成・パース・検証 に貼り付ければ次回 5 回の発火を確認できる。デプロイ前のチェックに便利である。
Cron 構文の分解——5 つのフィールド
cron 表現は空白で区切られた 5 つのフィールドとコマンドからなる。各フィールドがスケジュールの一部分を制御する。本ガイドで紹介するあらゆるスケジューラがこの構文を踏襲している。
┌──────────── minute (0 - 59)
│ ┌────────── hour (0 - 23)
│ │ ┌──────── day-of-month (1 - 31)
│ │ │ ┌────── month (1 - 12 or JAN-DEC)
│ │ │ │ ┌──── day-of-week (0 - 6 or SUN-SAT; 0 and 7 both mean Sunday)
│ │ │ │ │
* * * * * command-to-run
覚え方:「分・時・日・月・曜」——左から右へ、小さい単位から大きい単位へ。
フィールドごとの許容値
| フィールド | 範囲 | エイリアス | 注記 |
|---|---|---|---|
| 分 | 0-59 | なし | 0 は「正時」を意味する |
| 時 | 0-23 | なし | 24 時間制、0 は深夜 0 時、12 は正午 |
| 日 | 1-31 | なし | その月に存在しない日は黙って発火しない(2 月 31 日など) |
| 月 | 1-12 | JAN, FEB, MAR, …, DEC | 大文字小文字を区別しない |
| 曜日 | 0-7 | SUN, MON, TUE, …, SAT | 0 と 7 はいずれも日曜 |
演算子の詳細
5 つの演算子で標準的な cron 表現はすべて書ける。
| 演算子 | 意味 | 例 | 展開結果 |
|---|---|---|---|
* | 任意の値 | * * * * * | 毎分 |
, | リスト | 0 9,12,17 * * * | 09:00, 12:00, 17:00 |
- | 範囲(両端含む) | 0 9-17 * * * | 09:00 から 17:00 まで毎時 |
/ | ステップ | */15 * * * * | 分 0, 15, 30, 45 |
| 組み合わせ | 複合 | 0 9-12,14-17 * * * | 午前と午後(昼休みを除く) |
ステップ演算子は混乱しやすい。*/N はそのフィールドの最小値を起点としており、現在時刻ではない。*/15 は「毎時 0, 15, 30, 45 分」であって「いまから 15 分ごと」ではない。12:03 に保存しても、次回発火は 12:15 になる。基準値が * 以外の場合、5/15 は「5 から開始し、以降 15 ごと」と読み、分 5, 20, 35, 50 に発火する。
月名と曜日名
月と曜日は名前で書ける。大文字小文字は区別されない。
0 0 1 JAN,APR,JUL,OCT * # 各四半期の初日
0 9 * * MON-FRI # 平日 9 時
0 17 * * FRI # 金曜 17 時
コードレビューでは名前のほうが読みやすく、数値のほうがやや移植性が高い。プロジェクトごとに統一すること。
非標準マクロ:@reboot、@daily ほか
ほとんどの cron 実装は 6 つのショートカットマクロを受け付ける。
| マクロ | 展開結果 | 意味 |
|---|---|---|
@yearly / @annually | 0 0 1 1 * | 年 1 回、1 月 1 日深夜 0 時 |
@monthly | 0 0 1 * * | 毎月 1 日深夜 0 時 |
@weekly | 0 0 * * 0 | 毎週日曜深夜 0 時 |
@daily / @midnight | 0 0 * * * | 毎日深夜 0 時 |
@hourly | 0 * * * * | 毎時 0 分 |
@reboot | (特別) | cron デーモン起動時に 1 回 |
これらのマクロは非標準である。vixie cron と cronie はサポートするが、Kubernetes CronJob、GitHub Actions、AWS EventBridge は対応しない。可搬性が必要なら 5 フィールド形式で書くこと。@reboot は cron デーモンが init プロセスでないことが多いコンテナ環境では機能しない場合が多い。
50+ コピペ用 Cron 表現(用途別)
クイックリファレンス表は一般的なケース向けである。本節ではより密度の高い cron ジョブ例を 6 つのカテゴリに分けて挙げる。
N 分ごと
* * * * * # every minute
*/2 * * * * # every 2 minutes
*/5 * * * * # every 5 minutes — the cron expression every 5 minutes case
*/10 * * * * # every 10 minutes
*/15 * * * * # every 15 minutes
*/30 * * * * # every 30 minutes
0,30 * * * * # explicit minutes 0 and 30 (same as */30)
*/45 * * * * # WARNING: fires at 0 and 45 only, then wraps
*/45 はよくある落とし穴である。分は 0-59 なので 0 と 45 でしか発火せず、次の時間に折り返してしまう。45 分間隔で動かしたければ外部ワーカーが必要になる。
1 時間ごとのバリエーション
0 * * * * # every hour at :00
30 * * * * # every hour at :30
0 */2 * * * # every 2 hours, even hour
0 */6 * * * # every 6 hours
0 */12 * * * # twice a day at 00:00 and 12:00
15 */2 * * * # every 2 hours, offset by 15 min (avoids :00 spike)
毎日の指定時刻
0 0 * * * # midnight (= @daily / @midnight)
30 2 * * * # 02:30 — low-traffic batch window
0 9 * * * # 09:00
45 23 * * * # 23:45 — end-of-day rollups
0 9,12,17 * * * # three times daily
0 9-17 * * * # every hour from 09:00 through 17:00
週次スケジュール
0 9 * * 1-5 # weekdays at 9 AM
0 9 * * 0,6 # weekends at 9 AM
0 18 * * 5 # Fridays at 6 PM
0 0 * * 0 # Sunday at midnight (= @weekly)
0 9 * * MON,WED,FRI # Mon/Wed/Fri at 9 AM
*/30 9-17 * * 1-5 # every 30 min, business hours, weekdays
月次と四半期
0 0 1 * * # 1st of month at midnight (= @monthly)
0 0 15 * * # 15th — payroll window
0 0 1,15 * * # 1st and 15th — semi-monthly
0 0 1 */3 * # quarterly: first of Jan, Apr, Jul, Oct
0 0 1 JAN,APR,JUL,OCT * # same, named months
0 0 28-31 * * # last few days — pair with a date-check wrapper
POSIX に「月末」を表すネイティブな表現は存在しない。date -d tomorrow +%d = 01 を判定するラッパーを書くか、ネイティブ対応のスケジューラを使うこと(Quartz には L がある。Kubernetes には無い)。
年次とマクロのショートカット
0 0 1 1 * # Jan 1 at midnight (= @yearly / @annually)
0 0 25 12 * # Christmas at midnight
@yearly # = 0 0 1 1 *
@monthly # = 0 0 1 * *
@weekly # = 0 0 * * 0
@daily # = 0 0 * * *
@hourly # = 0 * * * *
@reboot # special: once on daemon start (vixie cron only)
これらの表現はすべて Crontab ジェネレーター — cron 式の生成・パース・検証 に貼り付ければ次回 5 回の発火が確認できる。デプロイ前のスモークテストに使える。
Cron vs systemd タイマー vs クラウドスケジューラ——選定マトリクス
cron はデフォルトの選択肢ではあるが、常に最善とは限らない。代表的な 7 つのスケジューラを比較する。cron vs systemd タイマーの判断、Kubernetes CronJob vs Vercel cron job の選定、crontab からマネージドクラウドへの移行などに使える。
| 機能 | vixie cron | systemd timer | K8s CronJob | GHA schedule | AWS EventBridge | Vercel Cron | Cloudflare Workers |
|---|---|---|---|---|---|---|---|
| フィールド構文 | 5 フィールド POSIX | OnCalendar 仕様 | 5 フィールド POSIX + timeZone | 5 フィールド POSIX | 6 フィールド Quartz、? 必須 | 5 フィールド POSIX | 5 フィールド POSIX |
| 最小間隔 | 1 分 | 1 秒 | 1 分 | ベストエフォート、15 分以上推奨 | 1 分 | 1 分(Pro プラン) | 1 分 |
| 明示的タイムゾーン | CRON_TZ= | Persistent=true | spec.timeZone(1.27+) | UTC のみ | ScheduleExpressionTimezone | UTC のみ | UTC のみ |
| 未実行リカバリ | 無し(anacron 利用) | 有り(Persistent=true) | 有り(startingDeadlineSeconds) | 無し | 有り | 無し | 無し |
| リトライ/バックオフ | 無し | 部分対応 | 有り(backoffLimit) | 失敗時リトライ | 有り | 無し | 有り |
| 同時実行制御 | 無し(flock 利用) | 部分対応 | 有り(concurrencyPolicy) | 無し | 無し | 無し | 無し |
@reboot サポート | 有り | 有り(OnBootSec= 経由) | 無し | 無し | 無し | 無し | 無し |
systemd タイマー——cron より優先する場面
systemd ベースの Linux では、タイマーは有力な代替手段となる。読みやすいカレンダー構文、ジャーナル統合、未実行リカバリを備えている。タイマーと対応するサービスは次のとおり。
# daily-report.timer
[Unit]
Description=Run daily report at 9 AM
[Timer]
OnCalendar=*-*-* 09:00:00
Persistent=true
Unit=daily-report.service
[Install]
WantedBy=timers.target
# daily-report.service
[Unit]
Description=Daily report job
[Service]
Type=oneshot
ExecStart=/usr/local/bin/daily-report.sh
User=reporter
systemctl enable --now daily-report.timer で有効化する。Persistent=true が cron との差を生む。マシンが 9 時に停止していても、起動直後にタイマーが発火する。vixie cron では anacron 無しに同等のことはできない。サービスのハードニングについては セキュリティのベストプラクティス を参照のこと。
Kubernetes CronJob
Kubernetes は POSIX スケジュールを、同時実行制御・履歴・明示的タイムゾーンといったプリミティブで包む。
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-report
spec:
schedule: "0 2 * * *"
timeZone: "America/New_York" # Kubernetes 1.27+
concurrencyPolicy: Forbid # never run two at once
startingDeadlineSeconds: 300 # skip if delayed >5 min
jobTemplate:
spec:
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: reporter
image: reporter:1.4.0
command: ["/usr/local/bin/report.sh"]
concurrencyPolicy: Forbid が flock の代わりとなる。これを設定しないと、長時間稼働するジョブが次のジョブと積み重なる。設定項目の一覧は「Kubernetes CronJob フィールドリファレンス」を参照。
GitHub Actions schedule の注意
GitHub Actions は標準の 5 フィールド POSIX cron を受け付ける。
on:
schedule:
- cron: '0 9 * * 1-5' # weekdays at 9 AM UTC
ベストエフォート動作である。GitHub ランナーが高負荷だと、ジョブは数分遅れたりスキップされたりする。15 分未満の間隔は避けること。タイムゾーン設定は無く、常に UTC になる。
AWS EventBridge——Quartz スタイルの 6 フィールド
AWS EventBridge は Quartz 風の cron を採用しており、6 フィールドで、いずれかの日フィールドに ? が必須となる。
cron(0 9 * * ? *)
フィールド順は Minutes Hours Day-of-month Month Day-of-week Year。一方の日フィールドが制限されている場合、他方は ? でなければならない(POSIX の OR 曖昧性を Quartz が解決する方式である)。Linux の crontab からそのままコピーしても検証で失敗する。
Vercel Cron、Cloudflare Workers、Render Cron Jobs
サーバーレスプラットフォームは 5 フィールド POSIX に揃えている。Vercel cron job は vercel.json に { "crons": [{ "path": "/api/cron/nightly", "schedule": "0 2 * * *" }] } として書く。Cloudflare Workers Cron Triggers は wrangler.toml を使う。
[triggers]
crons = ["*/15 * * * *", "0 9 * * 1-5"]
Render は render.yaml を使う。3 つすべてが UTC で動作し、スケジュールごとのタイムゾーン上書きは無い。最初から UTC で設計すること。
Cron デバッグの 7 つの罠(と捕まえ方)
「cron ジョブが動かない」という報告の大半は、7 つの根本原因のいずれかに当てはまる。スケジューラを疑う前に、まずこのリストを上から確認するとよい。
罠 1:PATH が最小限
cron はジョブを最小限の $PATH(典型的には /usr/bin:/bin)で起動する。インタラクティブシェルには /usr/local/bin、~/.cargo/bin、.bashrc の項目が十数個入っているが、cron からはどれも見えない。cron デバッグにおける PATH 環境変数問題は最も多い原因である。
症状は node: command not found。対策は crontab の先頭で PATH を指定するか、絶対パスを使うこと。
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin
*/15 * * * * /usr/local/bin/poll-api.sh
0 9 * * * /home/deploy/.cargo/bin/my-rust-cli
罠 2:stdout と stderr が黙って消える
デフォルトでは cron の出力は誰も読まないメールスプールに送られる。ジョブは黙って失敗する。両方のストリームをリダイレクトしておく。
*/15 * * * * /usr/local/bin/job.sh >> /var/log/job.log 2>&1
JSON 出力なら jq に通し、ログ行の抽出には 正規表現チートシート を参照する。systemd タイマーなら journalctl -u your-timer.service で出力を拾える。
罠 3:開発環境と本番環境のタイムゾーンのずれ
ニューヨークのノート PC で 0 9 * * * と書き、米国東部時間の 9 時を想定した。だがサーバーは UTC で動いている。cron は UTC の 9 時、つまり米国東部時間の 4 時に発火し、誰も気づかないうちに終わる。対策はサーバーを UTC に統一して UTC でスケジュールを書くか、明示的にタイムゾーンを固定することである。
CRON_TZ=America/New_York
0 9 * * * /usr/local/bin/morning-report.sh
CRON_TZ は vixie cron 3.0 以降で動く。Kubernetes 1.27 以降は spec.timeZone、AWS EventBridge は ScheduleExpressionTimezone を持つ。GitHub Actions は常に UTC。UTC、DST、エポック計算については Unix タイムスタンプガイド を参照のこと。
罠 4:エスケープされていない %
cron はエスケープされていない % を改行として扱い、それ以降の行をコマンドの標準入力として渡してしまう。そのため date +"%Y-%m-%d" は壊れる。すべての % を \% でエスケープするか、ロジックをスクリプトに切り出すこと。
0 0 * * * echo "Run at $(date +"\%Y-\%m-\%d")" >> /tmp/log
罠 5:実行の重なり
*/5 * * * * のジョブが時々 7 分かかるとすると、前回が終わらないうちに次が開始される。2 つのコピーが同じ行、ロックファイル、API クォータを取り合うことになる。flock で直列化する。
*/5 * * * * flock -n /tmp/job.lock /usr/local/bin/job.sh
-n はロックが保持されている場合即座に終了する。Kubernetes では concurrencyPolicy: Forbid を設定する。ロックファイルの権限にも気を配る。セキュリティのベストプラクティス を参照。
罠 6:コンテナ内の @reboot
@reboot は cron デーモン起動時に 1 回実行される。VM ではブート時に対応するが、コンテナでは cron デーモンが PID 1 でないことが多く、そもそも動かない場合もある。コンテナ内で @reboot は使わないこと。起動時 1 回実行のロジックは、entrypoint か init コンテナに置く。
罠 7:POSIX の日/曜日の OR セマンティクス
事故が長引きやすい cron の罠。POSIX のルール:日と曜日の両方が制限されている(いずれも * でない)場合、スケジュールはどちらかが一致したときに発火する。
0 0 1 * 5 は「金曜日の 1 日深夜 0 時のみ」に見えるが、実際は 1 日かつ毎週金曜日に発火する。月に 6〜10 回の余分な発火が発生する。
# WRONG: looks like "1st of the month, only if Friday"
0 0 1 * 5
# RIGHT: pick one constraint
0 0 1 * * # every 1st of the month
0 0 * * 5 # every Friday
# AND semantics need a wrapper
0 0 1-7 * 5 [ "$(date +\%u)" = "5" ] && /script # first Friday only
怪しい表現は Crontab ジェネレーター — cron 式の生成・パース・検証 に貼り付けるとよい。次回発火プレビューで OR トラップが見える。
現代のスケジューラ——Cron を使うべきでない場面
cron は「決まった頻度で、おおよそこの時刻にこのコマンドを実行する」という用途には適している。一方で、隣接する問題には向かない。
- 依存関係のあるワークフロー(A を実行し、A が成功したら B を実行)→ Airflow、Prefect、Dagster。
- リトライ、指数バックオフ、デッドレターキュー → Temporal、AWS Step Functions、Sidekiq。
- 分未満の間隔 → 反復間でスリープする長期稼働ワーカー。
- 秒単位の精度 → 専用デーモン。マネージドスケジューラは正確なタイミングを保証しない。
- イベント駆動の処理 → webhook、メッセージキュー、CDC ストリーム。
cron が消えるわけではない。Airflow、Step Functions、Sidekiq はいずれもワークフローの入口で cron 表現を受け付ける。5 フィールド文法は再利用できる。
Kubernetes CronJob フィールドリファレンス
上の選定マトリクスでは最小限の CronJob を示した。kubernetes cronjob 構文のフィールドリファレンスを以下に示す。
| フィールド | デフォルト | 動作 |
|---|---|---|
schedule | 必須 | POSIX 5 フィールド cron 表現 |
timeZone | コントローラ TZ | 明示的タイムゾーン(1.27+)、IANA 名を使用 |
concurrencyPolicy | Allow | Forbid は前のジョブ稼働中の新規発火をスキップ、Replace は前を中止 |
startingDeadlineSeconds | 無制限 | この遅延を超えたらスキップ |
successfulJobsHistoryLimit | 3 | 保持する成功 Job 数 |
failedJobsHistoryLimit | 1 | 保持する失敗 Job 数 |
suspend | false | 削除せず一時停止 |
backoffLimit | 6 | Job が Failed と判定されるまでの Pod リトライ数 |
activeDeadlineSeconds | 未設定 | Pod 実行時間の上限 |
ttlSecondsAfterFinished | 未設定 | この秒数経過後に Job を自動削除 |
よくある落とし穴が 2 つ。timeZone を忘れると、スケジュールが kube-controller-manager ホストのタイムゾーンに従ってしまう(マネージド Kubernetes では予測しにくい)。1 分間隔のスケジュールでは、デフォルトの successfulJobsHistoryLimit: 3 のままだと、ttlSecondsAfterFinished を設定しない限り毎分 3 つの Job オブジェクトが溜まり続ける。
クロスプラットフォームの Cron 等価物
macOS launchd。 Apple は cron より launchd を推奨している。launchd のジョブは ~/Library/LaunchAgents/ に置く .plist ファイルである。
<plist version="1.0"><dict>
<key>Label</key><string>com.example.daily</string>
<key>ProgramArguments</key><array><string>/usr/local/bin/daily.sh</string></array>
<key>StartCalendarInterval</key>
<dict><key>Hour</key><integer>9</integer><key>Minute</key><integer>0</integer></dict>
</dict></plist>
launchctl load ~/Library/LaunchAgents/com.example.daily.plist で読み込む。cron と違い、launchd はスリープ/復帰後に未実行ぶんを補う。
Windows タスクスケジューラは schtasks を使う。
schtasks /create /tn "DailyReport" /tr "C:\scripts\report.bat" /sc DAILY /st 09:00
schtasks /create /tn "EveryFifteen" /tr "C:\scripts\poll.bat" /sc MINUTE /mo 15
WSL 上ではネイティブ Linux cron も動くが、セッション終了時に停止する。常時起動の WSL ジョブを動かす場合はタスクスケジューラを使う。
Docker コンテナ内の Cron。 スリムイメージ(alpine、debian-slim、distroless)には cron デーモンが入っていないものが多い。cronie か busybox-cron をインストールし、tini または s6-overlay で PID 1 として動かすか、もしくは Kubernetes CronJob を使うほうが扱いやすい場合が多い。
上級者向けのコツとパターン
月末
cron に「月末」を表すネイティブ演算子は無い。28-31 の範囲で毎日実行し、翌日が 1 日かどうかを確認する。
0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/eom.sh
月の第 N 曜日
「第 1 月曜日」も同じラッパーパターンを使う。1-7 日に制限してから、曜日を判定する。
0 9 1-7 * * [ "$(date +\%u)" = "1" ] && /usr/local/bin/first-monday.sh
「最終金曜日」なら 25-31 日に制限し、加えて曜日チェックを行う。
負荷分散のためのランダムオフセット
多数のマシンが同じ cron を実行する場合、0 0 * * * だと UTC 深夜 0 時にサンダリングハードが発生する。ランダムな遅延を散らす。
RANDOM_DELAY=10 # cronie / anacron, in minutes
0 0 * * * /usr/local/bin/job.sh
0 0 * * * sleep $((RANDOM \% 600)); /usr/local/bin/job.sh # portable
ハートビート監視
cron は黙って失敗する。デッドマンズスイッチ・パターン:ジョブが正常終了するたびに監視サービスへ ping を送り、期待された ping が届かないときにサービスが警告する。Healthchecks.io、Cronitor、Dead Man’s Snitch は無料プランがある。
*/15 * * * * /usr/local/bin/job.sh && curl -fsS --retry 3 https://hc-ping.com/your-uuid
レスポンスコードで分岐する監視ロジック(200 は正常、429 はレート制限、503 は劣化)については HTTP ステータスコード チートシート を参照のこと。
冪等性はスケジューラではなくジョブの性質
cron にはリトライも、未実行リカバリも、同時実行制御も無い。信頼できる対策は、ジョブ自体を何度実行しても安全に作ることである。「9 時に今日のレポートを送る」ではなく「まだ送っていなければ今日のレポートを送る」と設計すれば、未実行も、重複も、手動キャッチアップも同じ結果に落ち着く。
FAQ
*/5 * * * * は本当に 5 分ごとか?
ほぼそうだ —— */5 * * * * は分 0 を基準としており、「いまから 5 分ごと」ではない。毎時 0, 5, 10, …, 55 分に発火する。ステップ */N はそのフィールドの最小値からの相対位置であり、現在時刻からではない。12:03 に保存しても次回発火は 12:08 ではなく 12:05 になる。
0 0 * * * は cron で何を意味するか?
0 0 * * * はサーバーのローカルタイムゾーンで毎日深夜 0 時(00:00)を意味する。フィールドは、分 0、時 0、日は任意、月は任意、曜日は任意。マクロ @daily や @midnight と等価。タイムゾーンを固定するには、crontab の先頭に CRON_TZ=America/New_York を追加すればよい。
30 秒ごとに cron ジョブを動かすには?
標準の POSIX cron では不可能で、最小粒度は 1 分である。回避策は 3 つ。* * * * * で 2 つのジョブを千鳥配置し、一方には sleep 30 && をつける。OnCalendar=*:*:0/30 の systemd タイマーを使う。あるいは、反復間でスリープする長期稼働ワーカーを書く。本番運用では長期稼働ワーカーが扱いやすい。
cron のデフォルトタイムゾーンは?
サーバーのシステムローカルタイムゾーン(/etc/timezone または TZ 環境変数)。UTC サーバーで 9 時の cron は、米国東部時間の 4 時に発火する。対策:crontab の先頭で CRON_TZ= を設定するか、サーバーを UTC に統一して UTC でスケジュールを設計する。GitHub Actions は常に UTC、Kubernetes 1.27 以降は spec.timeZone をサポートする。
cron ジョブが動かないのはなぜか?
cron ジョブが動かない場合、次の項目を順番にチェックする:cron デーモンが起動しているか(systemctl status cron)。crontab で $PATH が設定されているか。stderr が捕捉されているか(>> log 2>&1)。ユーザーの crontab が読み込まれているか(crontab -l)。コマンド内の % がエスケープされているか。タイムゾーンが想定どおりか。「動かない」報告のほとんどは 2 番目か 3 番目で解決する。
Kubernetes CronJob の構文は Linux cron と同じか?
schedule フィールドについては同じで、どちらも POSIX 5 フィールド cron を使う。Kubernetes は spec.timeZone(1.27+)、同時実行制御の concurrencyPolicy、未実行リカバリの startingDeadlineSeconds、一時停止の suspend: true を追加する。Linux cron はいずれも持たないので、代わりに flock と anacron を組み合わせる。
@reboot と @daily の違いは?
@daily は 0 0 * * * のマクロで、毎日深夜 0 時の固定スケジュールを意味する。@reboot は cron デーモン起動時に 1 回だけ実行され、繰り返しスケジュールを持たない。@reboot は vixie cron と cronie がサポートするが、Kubernetes CronJob、GitHub Actions、AWS EventBridge は非対応。コンテナ内では @reboot が発火しない場合が多い。
cron と crontab の違いは何だ?
cron はスケジュール済みジョブを実行するバックグラウンドのデーモンで、crontab はそれらをリストするファイル(そしてそのファイルを編集する crontab コマンド)。デーモンは各ユーザーの crontab を一定間隔で読み込み、実行時刻が cron 表現に一致するコマンドを実行する。要するに、cron がエンジンで、crontab がレシピだ。