WordPress WP-Cron(疑似Cron)の仕組みと問題点

WordPress標準のWP-Cron(疑似Cron)からOSのCronに切り替えようとしているときの覚書。
Gemini 3 Flash Previewと対話。

環境: FreeBSD 14.3-RELEASE-p8, WordPress 6.9.4


参考記事



WordPress 擬似Cron(WP-Cron)が実装された背景

WordPressが擬似Cronを採用した最大の理由は、サーバー環境に依存せず、PHPだけで完結させるため。

  • ホスティング環境の制約:
    世界中の多種多様な共有サーバー(安価なレンタルサーバーなど)では、ユーザーがOSレベルの crontab を設定できないケースが多々ある。
  • ゼロ構成での動作:
    インストールした瞬間に、予約投稿やアップデート確認などのバックグラウンドタスクが動作し始める必要。
  • ポータビリティ:
    サーバーの仕様を知らなくても、WordPressというアプリケーションのレイヤーだけで完結するスケジュール機構が求められた。


WordPress 擬似Cron(WP-Cron)の仕組み

WP-Cronは、バHTTPリクエストをトリガーとしたイベント駆動型で動作。

擬似Cronの処理手順

  1. リクエストの受信:
    ユーザーがサイトのいずれかのページにアクセス。
  2. 実行判定:
    WordPressの初期化プロセス(initフック等)の中で、前回の実行時刻を確認し、「実行すべきタスクがあるか」をDB(wp_optionsテーブル)に問い合わせる。
  3. 非同期実行(ループバック):
    実行すべきタスクがある場合、WordPressは自分自身に対してループバックHTTPリクエスト(wp-cron.phpへのPOST)を発行。
  4. タスク処理:
    wp-cron.php が独立したPHPプロセスとして起動し、予約されたタスクを順次実行。


WordPress 擬似Cron(WP-Cron)の構造的な問題点

技術的負債

  • オーバーヘッドとDB負荷:
    あらゆるページビュー(PV)のたびに、DBへの「タスク確認用SELECT」が発生。
    高トラフィックサイトでは、これだけでDBのI/Oを圧迫。
  • レースコンディション(競合状態による不安定化)とDBロック:
    同時アクセスが極めて多い場合、複数のリクエストが同時に「実行すべきタスクあり」と判断し、複数の wp-cron.php が起動。
    同一のDBレコードを更新しようとしてデッドロックや競合(Race Condition)を引き起こす。
  • 実行の不確実性:
    「アクセスがあるまで実行されない」ため、アクセスの少ない深夜の予約投稿が失敗したり、逆にアクセスが集中したタイミングで重い処理が走り、サイトのレスポンスを悪化させたりする。


OS Cron(crontab)へ切り替えるべき理由

  • リソースの分離
    ユーザーのブラウジング(表示処理)と、バックグラウンド処理(管理処理)を完全に切り離し、表示速度を安定化させる。
  • 確実な定時実行
    トラフィックの有無に関わらず、1分単位・5分単位など厳密なスケジュールでタスクを実行できる。
  • DB負荷の最小化
    PVに比例したDB問い合わせがゼロになる。
    実行回数が「アクセス数(数万〜)」から「Cronの設定数(数百/日)」に激減する。
  • WP-CLIの活用
    OS Cron経由なら wp-cli を利用でき、HTTP経由のオーバーヘッド(Nginx/PHP-FPMのプロセス消費)なしでPHPバイナリとして直接実行可能。
  • ログの可視化
    OSレベルでの実行ログ出力や、エラー時の標準エラー出力(stderr)をメールで受け取るなど、監視が容易になる。


OS Cronへ移行した結果

「define('DISABLE_WP_CRON', true);」を設定するのを忘れずに。
複数サイトへ一括反映するには、生成AIにバッチスクリプトを作成してもらう。

頻発していた5xxエラーが大幅に減った(VTSで確認)。


▼ 関連記事