定期実行の設計 — cronで回すか、専用スケジューラに任せるか

定期実行の設計で陥りがちな失敗は、「とりあえずcron」から始まり、気づけば誰も全体像を把握できなくなることです。cronが適切な場面は確かにありますが、ジョブ間の依存・失敗検知・多重起動防止が必要になった時点で、専用スケジューラへの移行を判断すべきです。その判断軸と具体的な設計パターンを整理します。

cronに積み増して管理不能になる構造

ジョブ定義が分散して全体像が消える

複数のサーバーにまたがった本番環境で定期ジョブを管理するとき、crontabが各ホストに分散している状態は珍しくありません。バックアップスクリプトはAサーバー、集計バッチはBサーバー、ログ転送はCサーバー——という具合に、ジョブが増えるたびに「動けばよい」として追加されていきます。10台以上の環境でこれが繰り返されると、全体のジョブ一覧を誰も手元に持っていない状態になります。新たな担当者が引き継いだとき、何が動いているかを把握するだけで数日かかることは珍しくなく、それ自体がリスクです。

依存関係がスクリプト内に埋まる問題

ジョブAの完了後にジョブBを動かしたい、という依存がある場合、cronでは実行時刻のオフセットで代用するのが一般的です。「Aは02:00、Bは02:30」という設定は一見シンプルに見えますが、Aの処理時間が変動した瞬間に意味を失います。現場では、このオフセットが徐々に積み上がり、深夜帯のジョブが朝まで続くようなスケジュールに膨らんだという話をよく聞きます。依存がスクリプト内のsleepやwaitに埋め込まれると、後任の担当者には設計意図が伝わらず、変更のたびに読解コストが発生します。

変更管理の欠如が招く属人化

ジョブの追加・変更・削除がすべて個別サーバーへのSSH経由になると、変更履歴がどこにも残りません。誰かが手動で修正したcrontabは、AnsibleのPlaybookや構成管理ツールには反映されず、次の構築時に再現できなくなります。30環境以上を並列管理しているチームでは、このドリフトが積み重なり、「どのサーバーのcrontabが正」なのかを誰も判断できない状態に陥ることがあります。設計当初は問題なかった管理方法が、規模の拡大とともに技術的負債に変わる典型的なパターンです。

cronで足りる処理・専用スケジューラが要る処理の違い

cronが適している処理の条件

cronが適切な選択肢になるのは、ジョブが独立していて相互依存がなく、失敗時の再実行を手動でも許容できる場合です。ログのローテーション・一時ファイルの削除・証明書の有効期限確認といったメンテナンス系の処理がこれにあたります。失敗しても業務への影響が軽微で、翌日の確認で十分間に合う処理なら、cronのシンプルさはむしろ強みです。設定ファイルがテキスト一枚で済み、外部依存もなく、理解するコストが最も低い選択肢といえます。

専用スケジューラが必要になるサイン

以下のいずれかに当てはまると、cronでの管理は設計的に限界を迎えます。まず、ジョブ間に明確な実行順序や依存がある場合。次に、失敗時に自動再実行やアラート通知が求められる場合。さらに、複数サーバーにまたがって実行を調整する必要がある場合や、実行履歴・ログを一元管理したい場合です。バッチ処理の規模が大きくなり、1ジョブの実行が30分を超えるようになると、多重起動や実行漏れのリスクも顕在化してきます。これらの条件が一つでも該当するなら、スケジューラの見直しを検討する段階です。

移行判断のタイミングを見誤らない

専用スケジューラへの移行は、「困ってから」では遅い場合があります。構築フェーズで「将来ジョブが10本を超えるか」「ジョブ間依存が発生するか」という問いに一つでも「はい」と答えられる場合は、最初からジョブ管理ツールを選定すべきです。後から移行するコストは、最初から導入するコストの3〜5倍になることが多く、既存のcronジョブをそのまま移行できないケースも生じます。移行判断を先送りにするほど、撤退コストは高くなります。

比較表: cron / systemd timer / ジョブ管理ツールの向き不向き

3つの選択肢の位置づけ

定期実行の実装選択肢は大きく3つに分かれます。「cron」は最もシンプルで、ほぼすべてのLinux環境に標準搭載されています。「systemd timer」はsystemdが管理するLinux環境で使え、ログ管理やサービスとの統合が強みです。「専用ジョブ管理ツール(Airflow・Rundeck・Temporal等)」は、ジョブ間の依存表現・実行履歴・通知・リトライを一元管理できます。それぞれに向いている規模と用途があり、どれが優れているかではなく「今の要件にどれが合うか」で選ぶことが重要です。

機能比較

観点 cron systemd timer 専用ジョブ管理ツール
導入コスト ほぼゼロ(標準搭載) 低(systemd環境のみ) 中〜高(別途構築・学習コスト)
ジョブ間依存 非対応(時刻オフセットで代用) After/Beforeで限定的に可能 DAG・パイプラインとして定義可能
失敗検知・通知 MAILTO設定のみ(貧弱) OnFailure=でUnit起動可能 Webhook・Slack通知等を内蔵
実行履歴・ログ管理 自前実装が必要 journalctlで参照可能 UIとAPIで一元確認
多重起動防止 自前でロック実装が必要 Type=oneshotで制御可能 concurrency制御が組み込み
複数ホスト管理 非対応(ホスト単体) 非対応(ホスト単体) 分散実行・Agentモデルに対応
向いている規模感 独立ジョブ10本未満 systemd環境の中規模 依存あり・大規模・複数環境

ツール選定の判断軸

ツール選定で迷う場合は、「依存関係の複雑さ」と「失敗時の業務影響範囲」を軸に置くと判断しやすくなります。ジョブが独立していて失敗しても業務が止まらないならcronで十分です。systemd timerは、同一ホスト上のサービス起動順序と連携させたい場面や、journaldによるログ統合が求められる場面で有効です。依存が複雑で失敗が業務に直結する場合は、専用ツールへの投資を惜しむべきではありません。選定の理由を設計書に記録しておくことも、後任の担当者への引き継ぎとして重要な判断の一つです。

依存関係・順序をどう表現するかの判断

依存をスクリプトに埋め込む危うさ

cronで複数ジョブを連携させるとき、よく見られる実装がシェルスクリプト内でのジョブ連鎖です。スクリプトAの末尾でスクリプトBをSSH越しに呼び出す実装は、一見動作しますが、依存関係が実行コードの中に埋まってしまいます。この状態では、「ジョブAとBの間に新たなジョブを挿入する」という変更が、スクリプト内部を読み解かないと判断できません。変更コストが高い上に、依存が壊れても検知できないという二重のリスクを抱えます。

DAGとして依存を表現する意義

専用スケジューラが提供するDAG(有向非巡回グラフ)による依存表現は、設計の可読性を根本から変えます。「ジョブBはジョブAの成功後に実行する」という意図が、コードではなく設定として外在化されます。これにより、ジョブの追加・変更・削除が設定の修正で完結し、既存のスクリプトを触らずに済みます。依存の追加がレビュー可能な設定ファイルで確認できるため、設計変更時のリスクが下がり、全体の依存グラフをUI上で可視化できることも、運用段階での問題切り分けに役立ちます。

依存表現の設計パターン

依存の表現には大きく3つのパターンがあります。「ファイルの存在確認」はシンプルで、前段ジョブが出力ファイルを置いたら後段が起動します。「APIやキューを介した連携」はジョブ間が疎結合になりますが、仲介コンポーネントが必要です。「スケジューラのDAG定義」は最も明示的で、依存の全体像が可視化されます。規模と運用体制に応じて選びますが、「依存がある時点でスクリプト内に埋め込まない」という原則を設計の起点に置くことで、後々の変更コストを抑えられます。

失敗検知・再実行をどう設計に組むか

通知設計をジョブ本体から分離する

cronのMAILTO機能でメール通知するだけでは、通知の見落としが多発します。担当者が変わったとき、あるいはメールが大量に来て埋もれたとき、失敗を検知できません。通知はジョブ本体のコードから分離して設計することが重要です。ジョブは成功・失敗を終了コードで返し、その終了コードを受け取った外側の仕組みが通知先(Slackチャンネル・PagerDutyなど)に送る構造にすると、通知ルールの変更がジョブ本体に影響しません。通知先・エスカレーション先を設計段階で明示的に決めておくことが、運用フェーズのトラブル対応時間を短縮します。

再実行の設計判断

再実行は「自動」か「手動トリガー」かの選択が必要です。自動再実行を設計する場合、まず「このジョブは複数回実行しても安全か(冪等か)」を確認します。冪等でないジョブを自動再実行すると、データの重複・二重処理・整合性の破壊につながります。3回試みて失敗した場合はアラートを上げて手動介入を求める、という設計が多くの現場で採用されています。再試行回数・間隔・上限は設計段階で明示的に決め、スクリプト内に暗黙に埋め込まない方針が肝心です。

冪等性を最初から設計に組む

バッチ処理の冪等性を担保するには、「処理済みフラグ」か「処理対象を一意IDで管理する」かが基本的なアプローチです。CSVファイルを取り込むバッチであれば、ファイル名とハッシュ値をDBに記録し、同一ファイルの再処理を防ぐ実装が有効です。外部APIへのリクエストを伴う場合は、idempotency keyをリクエストに付与することで、ネットワーク障害による二重送信を防げます。冪等性はジョブ設計の最初に決める属性であり、後付けで追加するのが難しい性質を持つことを念頭に置く必要があります。

多重起動・実行漏れを防ぐ設計

多重起動が引き起こす問題

定期ジョブの多重起動は、「前回の実行がまだ終わっていないのに次の実行が始まる」状態です。処理が重くなった、DBが遅い、外部APIの応答が遅延した——どの要因でも発生します。5分間隔のジョブが6分かかり始めた瞬間、2つのプロセスが同じデータを操作し始めます。商品在庫のバッチ処理でこれが起きると、在庫数の不整合が生じます。構築を任されたある担当者から、多重起動に気づかないまま数日間データ不整合が続いていたという話を聞くことがあります。設計段階での対処が求められる問題です。

ロック機構の設計と解放漏れの落とし穴

多重起動を防ぐ実装として最もよく使われるのは、ファイルロック(flock)です。ジョブ起動時にロックファイルを作成し、すでに存在する場合は起動を見送ります。systemd timerのType=oneshotも同様の効果を持ちます。専用ジョブ管理ツールでは、concurrencyをパラメータとして設定でき、「最大1並列」を宣言的に指定できます。どの手段を選ぶにせよ、プロセスが異常終了してロックが解放されない場合の対処——ロックファイルの自動削除や期限設定——を設計に含めることが必要です。この対処を忘れると、永続的にジョブが起動しなくなるという落とし穴があります。

実行漏れを検知する逆転の発想

多重起動と逆の問題が「実行漏れ」です。cronのジョブはデフォルトでは「実行した」という記録を残しません。サーバーが再起動した、crondが停止した——という状況でジョブが抜けても、誰も気づきません。設計として有効なのは、ジョブが完了したタイミングでハートビートを外部監視サービスに送り、一定期間ハートビートがなければアラートを上げる仕組みです。この「死活監視の逆転発想」は実行漏れ検知の標準パターンとして広く採用されています。「ジョブが動いた記録」ではなく「ジョブが動いていない状態」を検知することが、設計の要点です。

定期実行設計チェックリスト

設計フェーズで以下の項目を確認することで、運用フェーズでのトラブルを大きく減らせます。ジョブを追加するたびに参照する台帳として活用してください。手を動かす具体的な実装手順はセミナーや専門書に任せ、ここでは設計判断の観点に絞っています。

  1. ジョブ一覧を台帳化しているか — 全ジョブをリスト化し、実行時刻・対象サーバー・担当者・最終更新日を記録する。誰でも参照できる場所に置く。
  2. ジョブ間の依存を明示しているか — 依存関係をスクリプト内に埋め込まず、設定や台帳で外在化する。時刻オフセットによる代用をしていないか確認する。
  3. スケジューラ選定の根拠を記録しているか — なぜcronを選んだか、あるいは専用ツールを選んだかを設計書に残す。ジョブ増加時の移行トリガーも明記する。
  4. 多重起動防止が実装されているか — flock・Type=oneshotなど何らかのロック機構が存在し、異常終了時のロック解放処理も含む。
  5. 失敗通知の宛先と経路が決まっているか — MAILTOだけでなく、Slackや監視ツールへの通知経路を設計する。担当者変更時に通知先も更新できる構造にする。
  6. 冪等性の有無を確認しているか — 自動再実行を設定する前に、ジョブが複数回実行されても安全かを検証する。冪等でない場合は再実行を手動に限定する。
  7. 実行漏れ検知の仕組みがあるか — ハートビート監視など、「実行されなかった場合」を検知できる設計が存在する。
  8. ログの保存場所・期間が定義されているか — 標準出力・標準エラーの保存先を決め、ローテーション設定を含む。後から追跡できる期間を明確にする。
  9. 変更管理の手順が決まっているか — crontabの変更をIaCや構成管理ツールで管理する運用が整っており、手動変更がドリフトを生まない体制になっている。
  10. ジョブ増加時の移行計画を持っているか — 現在cronで十分でも、ジョブが一定数を超えた場合や依存が発生した場合の移行トリガーを事前に定義する。

▶ 手を動かして本番まで到達する

脱属人化の第一歩は「読める・書けるスクリプト」から始まります

ここまでの設計判断は、読めば腹に落ちます。ですが「自分の手で本番まで通しきる自信」は、それとは別の話になります。

自動化の設計を、手を動かして身につける2日間です。手順書に閉じ込めた構築を、他人が読めて再現できる形へ変えていきます。

定期実行の設計を手を動かして組む2日間へ →

シェルスクリプトマスターセミナー|自動化の設計を手で身につける2日間