[WordPress] WP-Cronを本職のcronに任せる

wp-cron.phpへのリクエスト数が半端ない

WordPressは特定の時間になったら特定の処理を行うというタイマー的な機能を実装するにあたって、WP-CRONという仕組みを用意しています。これは通常WordPress上のいずれかのページへアクセスがあると、それと平行してwp-cron.phpへも同時にアクセスが発生し、その際に実行すべき処理があれば起動するというものです。つまりユーザーが1回アクセスすると必ず最低でも2回のアクセスが走ってしまう。

実際にアクセスログをざっくり集計すると、リクエストの27.5%程度がこのwp-cron.phpでした。

$ cat access_log | wc -l
82336
$ cat access_log | grep wp-cron.php | wc -l
22678

このブログはフロントにCDN(CloudFront)を置いているので、オリジンであるWordPressサーバには最小限のリクエストしか来ないのですが、拡張子に.phpが含まれる物はキャッシュ時間をゼロにして素通りさせている関係上、こいつだけはPV数分やってくるというわけです。そんなに上等なサーバ使ってないのでバズると死ぬw

というわけで、今回はwp-cron.phpへのアクセスを停止し、1分間に1回サーバ内部でWP-CRONを実行する設定をします。

wp-cron.phpへのリクエストを停止する

WordPressをインストールしたディレクトリ配下にある config.php を開き、適当な場所に以下のdefine行を追加します。

$ cd /web/wordpress
$ vi config.php
define('DISABLE_WP_CRON', true);

ちなみに設定する値はfalseにならなければ何でも大丈夫です。具体的には以下の関数でWP-CRONを実行するか判定しているのですが、このif文がtrueになれば問題ありません。

### ./wp-includes/cron.php 内のコード
function wp_cron() {
        // Prevent infinite loops caused by lack of wp-cron.php
        if ( strpos($_SERVER['REQUEST_URI'], '/wp-cron.php') !== false || ( defined('DISABLE_WP_CRON') && DISABLE_WP_CRON ) )
                return;

これでwp-cron.phpへのリクエストは止まったはずです。

cronからWP-CRONを起動する

このままだとバックアップ用のプラグインや、時間指定した記事が表示されなくなるっぽいのでWP-Cronを別の方法で動かしてやります。 LinuxなどUNIX系OSに搭載されているスケジューラであるcronの設定をしてWP-Cronを起動しようと思うのですが、ここではコマンドラインからWordPressを操作できるWP-CLIを利用したいと思います。

WP-CLIのインストール

公式サイトの内容に沿ってインストールします。

## ダウンロード
$ curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar

## 実行権を付与
$ chmod +x wp-cli.phar

## /usr/local/bin/へ移動しコマンド化
$ sudo mv wp-cli.phar /usr/local/bin/wp

動作確認をするのですが、カレントディレクトリをWordPressをインストールしたディレクトリに移動しておくか、インストール先のパスを指定する必要があります。WP-CLIはwpという名前のコマンドで叩くのが一般的です。--infoオプションで環境情報が表示されます。

$ cd /web/wordpress
$ wp --info
OS:     Linux 4.9.77-31.58.amzn1.x86_64 #1 SMP Thu Jan 18 22:15:23 UTC 2018 x86_64
Shell:  /bin/bash
PHP binary:     /usr/bin/php-7.1
PHP version:    7.1.23
php.ini used:   /etc/php.ini
WP-CLI root dir:        phar://wp-cli.phar/vendor/wp-cli/wp-cli
WP-CLI vendor dir:      phar://wp-cli.phar/vendor
WP_CLI phar path:       /web/wordpress
WP-CLI packages dir:
WP-CLI global config:
WP-CLI project config:
WP-CLI version: 2.1.0

ちなみにパスを指定する場合は以下です。

$ wp --info --path=/web/wordpress

cronから実行するシェルスクリプトの準備

cronから直接wpコマンドを叩いても良いのですが、今回はシェルスクリプトを1枚挟みます。

#!/bin/bash

#
# wp-cronをCLIから実行する
#

#---------------------------------------
# 定数
#---------------------------------------
# WORDPRESSをインストールしたディレクトリ
WP_ROOT='/web/wordpress'

#---------------------------------------
# 実行
#---------------------------------------
/usr/local/bin/wp cron event run --due-now --path=$WP_ROOT

実行権の付与を忘れずに。

$ chmod +x wpcron.sh

cronへ登録

先ほど作成したシェルスクリプトをcronに登録します。一般ユーザーで大丈夫です。以下のようにすると1分置きに実行してくれます。

## ファイルに記録しておく
$ cat crontab.txt
* * * * * /home/katsube/cron/wpcron.sh

## 登録
$ crontab < crontab.txt

## 登録状況を確認
$ crontab -l
* * * * * /home/katsube/cron/wpcron.sh

cronが起動しているか確認

/var/log/cronに記録されていますので、tailなどでのぞいて確認します。

$ sudo tail -f /var/log/cron
Dec 30 12:55:15 ip-172-26-11-162 crontab[29605]: (katsube) REPLACE (katsube)
Dec 30 12:55:18 ip-172-26-11-162 crontab[29606]: (katsube) LIST (katsube)
Dec 30 12:56:01 ip-172-26-11-162 CROND[29620]: (katsube) CMD (/home/katsube/cron/wpcron.sh)
Dec 30 12:57:01 ip-172-26-11-162 CROND[29627]: (katsube) CMD (/home/katsube/cron/wpcron.sh)
Dec 30 12:58:01 ip-172-26-11-162 CROND[29667]: (katsube) CMD (/home/katsube/cron/wpcron.sh)
Dec 30 12:59:01 ip-172-26-11-162 CROND[29708]: (katsube) CMD (/home/katsube/cron/wpcron.sh)

なお、このファイルは起動したかどうかしか記録されていませんので、正常に処理が行われたか調べるには出力結果をログなどに記録しておく必要があります。シェルスクリプトに手を入れて現在時間なども出力した方がわかりやすいですね。

$ cat crontab.txt
* * * * * /home/katsube/cron/wpcron.sh >> /tmp/wpcron.log 2>&1

結果確認

よし ( ´∀`)bグッ

$ cat access_log | grep wp-cron.php | wc -l
0
エンジニアのためのWordPress開発入門 (Engineer's Library)
野島 祐慈 菱川 拓郎 杉田 知至 細谷 崇 枢木 くっくる
技術評論社
売り上げランキング: 23,495