WordPress WP-Cron(疑似Cron)の仕組みと問題点
WordPress標準のWP-Cron(疑似Cron)からOSのCronに切り替えようとしているときの覚書。
Gemini 3 Flash Previewと対話。
環境: FreeBSD 14.3-RELEASE-p8, WordPress 6.9.4
参考記事
- WP-Cron(wp-cron.php)を無効にしてパフォーマンスを改善する方法| Kinsta
- Optimization – Advanced Administration Handbook | Developer.WordPress.org
WordPress 擬似Cron(WP-Cron)が実装された背景
WordPressが擬似Cronを採用した最大の理由は、サーバー環境に依存せず、PHPだけで完結させるため。
- ホスティング環境の制約:
世界中の多種多様な共有サーバー(安価なレンタルサーバーなど)では、ユーザーがOSレベルの crontab を設定できないケースが多々ある。 - ゼロ構成での動作:
インストールした瞬間に、予約投稿やアップデート確認などのバックグラウンドタスクが動作し始める必要。 - ポータビリティ:
サーバーの仕様を知らなくても、WordPressというアプリケーションのレイヤーだけで完結するスケジュール機構が求められた。
WordPress 擬似Cron(WP-Cron)の仕組み
WP-Cronは、バHTTPリクエストをトリガーとしたイベント駆動型で動作。
擬似Cronの処理手順
- リクエストの受信:
ユーザーがサイトのいずれかのページにアクセス。 - 実行判定:
WordPressの初期化プロセス(initフック等)の中で、前回の実行時刻を確認し、「実行すべきタスクがあるか」をDB(wp_optionsテーブル)に問い合わせる。 - 非同期実行(ループバック):
実行すべきタスクがある場合、WordPressは自分自身に対してループバックHTTPリクエスト(wp-cron.phpへのPOST)を発行。 - タスク処理:
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で確認)。