wp-cron の代わりは WP-CLI が最適だと思う

wp-cron の代わりは WP-CLI が最適だと思う 技術ネタ

wp-cron.php の最適な実行方法を探した時のことを書いています。



wp-cron.php の問題

wp-cron.php の問題は色々なサイトに書かれていますが、

  • 負荷問題
  • 攻撃の標的

などが主だったものだと思います。
当サイトでも、当初は wp-cron.php を 127.0.0.1 のみアクセス可能な状態にしていました。

一般的(?)な wp-cron.php の無効化と対策

一般的かどうかはわかりませんが、wp-cron.php の対策をググると、

  • curl や wget で cron.php を実行させる
  • cron.php を直接実行する

の2通りのいずれかを crontab に書いて実行するやり方を紹介しているサイトが多くありました。
これ自体を否定する訳ではありませんが、何となくスマートではなく、他の方法を探していました。

WP-CLI で cron を実行する方法がある

他の方法を調べていると、 WP-CLI という、WordPressをコマンドラインから操作する機能があることがわかりました。

もう少し詳細に調査したところ、cron を実行させる機能を持っていることがわかり、さらに、そのコマンドオプションとして「–due-now」が用意されているようで、これを指定すると、現在実行可能なもののみ実行してくれるようです。

具体的なやり方

まず、cron に登録されたイベントの一覧を、以下のコマンドで確認します。

cd {WordPressのドキュメントRoot}
wp cron event list

表示された結果の中の「next_run_relative」が「now」となっているものが実行待ちのものです。

+------------------------------------+---------------------+--------------------+------------+
| hook                               | next_run_gmt        | next_run_relative  | recurrence |
+------------------------------------+---------------------+--------------------+------------+
| wp_version_check                   | 2018-09-17 09:23:45 | 6 hours 16 minutes | 12 hours   |
| wp_update_plugins                  | 2018-09-15 21:23:45 | now                | 12 hours   |
| wp_update_themes                   | 2018-09-15 21:23:45 | now                | 12 hours   |
+------------------------------------+---------------------+--------------------+------------+

↑は例になりますが、この例では、3つの内「wp_update_plugins」と「wp_update_themes」の2つが実行待ちの状態になっています。
この状態で、以下のコマンドで、実行待ちのもの実行してみます。

cd {WordPressのドキュメントRoot}
/usr/local/bin/wp cron event run --due-now

実行すると、以下のようなログが表示されます。

Executed the cron event 'wp_update_plugins' in 0.055s.
Executed the cron event 'wp_update_themes' in 0.01s.
Success: Executed a total of 2 cron events.

きちんと「wp_update_plugins」と「wp_update_themes」のみ実行されたと表示され、「wp_version_check」は表示されていません。これで、「next_run_relative」が「now」のみのものが実行されたことがわかりました。

念のため、もう一度「wp cron event list」コマンドで、cron に登録されたイベントの一覧を確認すると、

+------------------------------------+---------------------+-----------------------+------------+
| hook                               | next_run_gmt        | next_run_relative     | recurrence |
+------------------------------------+---------------------+-----------------------+------------+
| wp_version_check                   | 2018-09-17 09:23:45 | 6 hours 12 minutes    | 12 hours   |
| wp_update_plugins                  | 2018-09-17 09:23:45 | 6 hours 12 minutes    | 12 hours   |
| wp_update_themes                   | 2018-09-17 09:23:45 | 6 hours 12 minutes    | 12 hours   |
+------------------------------------+---------------------+-----------------------+------------+

この通り、「wp_update_plugins」と「wp_update_themes」が「now」ではなくなっていることが確認できました。

これで思っている通りの挙動であることが確認できたため、crontab に登録します。
当サイトでは、5分毎に実行するように、KUSANAGI のユーザID の crontab に以下の通り登録しました。

*/5 * * * * cd {WordPressのドキュメントRoot} && /usr/local/bin/wp cron event run --due-now > /dev/null

登録したら、適当な時間を見計らって、「wp cron event list」コマンドで「next_run_gmt」が過ぎたものが「now」になっていれば問題なく実行されています。

wp-cron.php を無効にする

WP-CLI で実行する設定にしたら、もう wp-cron.php は不要になるので、wp-config.php に以下を追加し実行されないようにします。

define('DISABLE_WP_CRON', true);

これで終わりですが、当サイトでは、Nginx で wp-cron.php にアクセスできないようにも設定しています。

最後に

当サイトでは、しばらくこの状態で運用していますが、今のところ問題は出ていません。

個人的には wp-cron.php の代わりは WP-CLI で実行するのが最適だと考えています。
wp-cron.php をどうするか悩んでいる方がいれば参考にしていただければと思います。

また、cron もそうですが、WP-CLI は WordPress の運用のツールとしては非常に便利だと感じています。今後、オンラインで実行する必要がないものは、WP-CLI を前提にカスタマイズ(機能追加)していく予定です。