work.log

元エンジニアの備忘録的ブログ

Nginxで作成したキャッシュをWordPressから自動で削除する

投稿:2015-09-10 18:44  更新:

Nginx で作成するキャッシュファイルを WordPress の何らかのアクションを利用して自動削除する方法のメモ書きです。

下記記事で Nginx + WordPress を組み合わせたキャッシュ関連の設定を書きましたが、肝心なキャッシュ削除については考察で止まってましたのでその続きとなります。

この記事の内容は「Nginx を自由に設定できる」人向けです。

キャッシュ削除の概要

前回の考察で書いた内容そのままですが、このような仕組みで Nginx のキャッシュを削除する事にしました。

  1. WordPress の記事を投稿、もしくは更新をする
  2. 専用プラグインが上記アクションフックで JSON を飛ばす
  3. 削除 CGI が JSON を受信して該当ドメイン名のキャッシュを削除

削除 CGI は WordPress の配下ではなく、ip アドレスからアクセスできて Perl が動作する Web 領域を Nginx で別途構成しないといけないですが、これは複数台のリバースプロキシ型キャッシュサーバを立てた場合にでも対応できるようにとの思ったのと、WordPress とは別のサーバからリモート操作をするのにこっちの方が都合が良かったからです。

そしてこれが作ったキャッシュ削除用の WordPress プラグインと CGI です。

中身はこのようになっています。

nginx-cachepurge-client/
  |
  |
  |-- nginx-cachepurge-client.php *1
  |
  |-- nginx-purge.cgi *2
  |
  `-- includes/
      |
      |-- admin.php *3
      |
      `-- ncpc-functions.php *4
  1. プラグインのメインファイル、主に includes 配下のファイルを読み込んでいる
  2. Perl で書いたキャッシュを削除する CGI。これは別領域に置くので取り出しておく
  3. プラグインの管理画面を構成する PHP ファイル
  4. 削除機能を提供する PHP ファイル

キャッシュ削除のタイミングについて

次にキャッシュの削除タイミングについては WordPress の投稿に関するアクションフックを利用しています。

記事ページ、個別ページの「投稿と更新」動作をカバー出来ていれば大丈夫だろうという感じで下記の WordPress 関数をチョイス。

  • new_to_publish (新規投稿)
  • publish_to_publish (更新)
  • pending_to_publish (承認待ち -> 新規投稿)
  • draft_to_publish (下書き -> 新規投稿)
  • auto-draft_to_publish (自動下書き -> 新規投稿)
  • future_to_publish (予約投稿 -> 新規投稿)
  • publish_to_trash (投稿 -> ゴミ箱)

これで投稿系の操作を行うと自動でキャッシュが削除されます。

ちなみに、手動削除機能は面倒でプラグインに付けなかったので、キャッシュを手動削除したい時には適当な投稿記事で更新ボタンを推してあげれば消えます。

プラグインのインストールと設定

プラグインのインストールは WordPress の plugins ディレクトリにアップロードして有効化するだけ。

nginx-cachepurge-client-01

プラグインを有効化すると必要な情報が自動設定されるので 1 台構成なら特に触る必要もないですが一応、管理画面もあってちょっとした設定ができます。

nginx-cachepurge-client-02

Nginx の設定も絡むのでキャッシュディレクトリは決め打ちですが「/home/www/cache/」配下に作成されるディレクトリ名を指定する。これは前回の記事に書いてある「キャッシュキーの設定」に関する部分。なので Nginx の構成次第では動かないので注意。

キャッシュサーバ IP」はそこに設定された ip 全てに削除命令を飛ばすので複数台構成にするときはここも設定する。

CGIの設置

最後に付属している CGI ファイルは ip でアクセスできて Perl が実行できる Web 領域に配置。特にセキュリティを考慮していないのですが必要であれば別途アクセス制御等を。

前回の記事だと「/home/www/htdocs」がそれに該当しますのでそこに放り込んで、Perl の JSON モジュールをこんな感じにインストール。

# yum install perl-JSON

それと、Nginx で CGI を実行するために必要な環境を構築しておく必要もあります。

そして CGI はこんな内容となってます。

#!/usr/bin/perl

use strict;
use warnings;
use JSON;

    my $query = '';
    my $cache_dir = '/home/www/cache/';
    my $json = {};
    my @error = ();

    if ($ENV{'REQUEST_METHOD'} !~ /^POST$/i ||
        $ENV{'CONTENT_TYPE'} !~ /^(text|application)\/json$/) { &print_error(); }

    read (STDIN, $query, $ENV{'CONTENT_LENGTH'});
    if (!$query) { &print_error(); }

    $json = decode_json($query); 

    $cache_dir .= $json->{dir};

    if (-d $cache_dir) {

        if ($json->{verbose}) {
            @result = glob("$cache_dir/*/*/*");
        }

        @error = `/bin/rm -rf $cache_dir/* 2>&1`;

        if ($json->{verbose}) {

            $json = {
                msg   => 'success',
                purge => $cache_dir,
                file  => scalar(@result),
                error => \@error,
                flag  => 1
            };

        } else {
            $json = { flag => 1 };
        }

    } else {

        if ($json->{verbose}) {

            $json = {
                msg   => 'error: no such directory',
                purge => $cache_dir,
                flag  => 0
            };

        } else {
            $json = { flag => 0 };
        }

    }

    &print_json($json);

sub print_json {

    my $hash = shift || return 0;
    my $json = encode_json($hash);

    print "Content-type: application/json; charset=utf-8\n";
    print "X-Content-Type-Options: nosniff\n";
    print "\n";
    print "$json";

    exit;

}

sub print_error {

    print "Status: 400 Bad Request\n";
    print "Content-type: text/html\n";
    print "\n";
    print "<!DOCTYPE html>\n";
    print "<html lang='ja'>\n";
    print "<head>\n";
    print "<title>HTTP Error 400 - Bad Request</title>\n";
    print "</head>\n";
    print "<body>\n";
    print "<p>HTTP Error 400 - Bad Request</p>\n";
    print "</body>\n";
    print "</html>\n";

    exit;

}

exit;

プラグインがこの CGI へ POST する JSON の内容はこんな感じです。

{"dir":"worklog.be"}

こうすると、詳細な結果が取れるけどこれは主にデバッグ用とかで特に意味ない。

{"dir":"worklog.be","verbose":1}

実際の動作はキャッシュディレクトリを丸ごと「rm -rf *」しているだけなのでちょっと乱暴です。Nginx の cache manager process を無視して消しているのでこんなエラーログがでますが動作には問題なし。(半年近く運用してますが気になった事はないので多分大丈夫)

2015/09/10 03:44:06 [crit] 7018#0: unlink() "/home/www/cache/worklog.be/f/c9/0cd069433c2cb1b6197cd1270e86dc9f" failed (2: No such file or directory)

これで以上です。

おすすめのVPSサーバ

  • OSが選べる
  • VPS同士でLANが組める
  • 複数台構成向き

このブログで使っています。

  • 転送量が多いサービスに
  • 借りてるのは3年間一度もdown無し!

よく見られている記事

  • 本日
  • 週間
  • 月間