CakePHPでジョブキューするプラグイン

CakePHP Advent Calendar 2012の16日目の記事として書きます。前日の15日目は@longkey1さんの「俺流CakePHPセットアップ方法」でした。私は最近良くCakePHPでジョブキューする機会がありますので、そのプラグインについて書きます。

複雑なアプリケーションを構築していくと、なが~く時間のかかる処理をばんばん実行したいときがありますが、その際に以下が課題となってきます。

  • ユーザーを画面で待たせたくない→バックグラウンドで処理したい
  • CPUを専有する処理を同時に行いたくない
  • でも複数のサーバーで分散させて処理したい

これらはすべてジョブキューの仕組みを使えば解決できます。

ワーカーというジョブを処理するプロセスが、キューに溜まったジョブを入った順から(FIFO: First in, First out)処理してくれます。ワーカーのプロセスは複数のサーバーを並列にして起動できるので、複数のジョブをより効率的に処理したい場合にはワーカーを増やせます。

ではCakePHPでどうやってジョブキューを行い処理が行えるかというと、Ruby on RailsにはResqueというジョブキューの仕組みがありますが、その仕組みをCakePHPに移植したCakeResqueというプラグインがあります。なお、CakeResqueはCakePHP2.1以降向けのプラグインとなっていますので、CakePHP2.1以降を前提として利用方法を説明したいと思います。

Redisのインストール

CakeResqueを利用するにはジョブを格納する先としてNoSQLなKVSであるRedisをインストールする必要があります。Mac OSXへのインストール方法とCentOS 6.3へのインストール方法について説明しますが、他のLinuxディストリビューションでもパッケージ管理ツールから簡単にインストールできると思います。

なお、Redisは2.2以降が必要です。

Mac OSXへのインストールと起動

homebrewからインストール可能です。homebrewをインストールしていない方は、インストールを行なってください

homebrewが入っている方、入れた方は以下コマンドよりインストールできます。

$ brew install redis

インストール後、以下を実行することでRedisを起動できます。

$ /usr/local/bin/redis-server /usr/local/etc/redis.conf

CentOS 6.3へのインストールと起動

CentOSの標準リポジトリには入っていないので、remiリポジトリからインストールします。remiリポジトリを使いたくない方はソースからインストールできますが、この記事では割愛させていただきます。

remiリポジトリを追加していない方は以下のコマンドで追加できます。

$ sudo rpm --import http://rpms.famillecollet.com/RPM-GPG-KEY-remi
$ sudo rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
$ sudo rpm --import http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/RPM-GPG-KEY-EPEL-6
$ sudo rpm -ivh http://ftp.jaist.ac.jp/pub/Linux/Fedora/epel/6/x86_64/epel-release-6-7.noarch.rpm
$ sudo rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt
$ sudo rpm -ivh http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm

remiリポジトリが追加されている方、追加した方は以下のコマンドでインストールできます。

$ sudo yum install redis

インストール後、以下を実行することでRedisを起動できます。

$ sudo service redis start

CakeResqueのインストール

CakeResqueはCakePHPのプラグインとしてインストールする必要があります。インストール方法はgitを用いるか、ファイルをダウンロードして配置するか2つ方法がありますが、この記事ではgitを使ってインストールします。

インストールしたいCakePHPの /app/Plugin ディレクトリで以下を実行します。
$ git clone git://github.com/kamisama/Cake-Resque.git CakeResque
とりあえずファイルをダウンロードし配置した、という状態ですが依存しているライブラリがありますので以下を実行しそれらもインストールします。

※インストールにはPHPのモジュールであるPHP Archive(phar)が必要となります

$ cd CakeResque
$ curl -s https://getcomposer.org/installer | php
$ php composer.phar install

また、CakeResqueを使うには設定ファイルに記載が必要です。/app/Config/bootstrap.php に以下を記載します。

CakePlugin::load(array( # or CakePlugin::loadAll(array(
    'CakeResque' => array('bootstrap' => true)
));

最後に/app/Console/Command/AppShell.phpを修正する必要があります。AppModelクラスをインクルードすることと、performメソッドを記述する必要があります。

initialize();
        $this->{array_shift($this->args)}();
    }
}

以上でインストールが完了となります。

ジョブの実装

早速ジョブの実装に移ります。ジョブはAppShellクラスを継承し、任意のメソッド名で処理を記述します。作成したジョブは /app/Console/Command 配下に「クラス名.php」の名前で配置します。

以下は TestjobShell というクラスで testAction という名前のメソッドの例です。

args に配列として格納されます
        $value = isset($this->args[0]) ? $this->args[0] : '';
        $this->log('testAction value:'.$value, 'Testjob');
    }
}

ジョブの処理を確認するためにTestjobという名前でログを作成するようにしました。

ジョブをキューに入れる

コントローラーやシェルからジョブをキューに入れるには以下のようにします。第一引数には入れるキューの名前、第二引数にはジョブの名前、第三引数にはジョブに渡す引数を配列で指定します。引数の配列の1番目には呼び出すメソッド名を指定します。

CakeResque::enqueue('default', 'Testjob', array('testAction' 'Test value 1', 'Test value 2'));

以上でRedisが起動していればジョブはキューに入っています。この状態ではまだ処理は行われていません。なぜならワーカーのプロセスを起動していないからです。

ワーカーが動いていなくてもキューには入っていますので、後でワーカーが起動されればジョブは処理されます。次にワーカーを起動しましょう。

ワーカーの起動

以下のコマンドを、CakePHPがインストールされているディレクトリで実行することでワーカーが起動されます。

$ app/Console/cake CakeResque.CakeResque start

ディフォルトでは「default」という名前のキューでワーカーが起動されますが、別の名前のキューでワーカーを起動するには -q オプションのあとにキュー名を入れます。

その他のワーカーを操作するためのコマンドについては Cake Resque | Commands を参照してください。

先ほど入れたキューと同じ名前でワーカーを起動していれば、もうジョブは処理されたはずです。ログが出力されているか確認してみましょう。

$ tail app/tmp/logs/Testjob.log
2012-12-18 01:35:18 Testjob: testAction value:test1

注意点として、ワーカーを起動するとジョブはすべてインスタンス化されるようで、ジョブのPHPファイルを修正しても反映されません。ジョブを修正した場合は必ずワーカーを再起動しましょう。

ジョブをコマンドラインからキューに入れる

ジョブをとりあえず起動してみたいときや、より複雑な構成になると定期的にジョブを駆動させたいシーンがあると思います。その際にはコマンドラインからジョブをキューに入れることも可能です。

$ app/Console/cake CakeResque.CakeResque enqueue [キュー名] [ジョブクラス名] [メソッド名,引数,引数が複数ある場合はカンマ区切り]

ワーカーのステータスを確認する

ワーカーが動いているかの確認や、失敗したジョブがなかったかについてはコマンドラインから簡単にではありますが確認することができます。

$ app/Console/cake CakeResque.CakeResque stats
Resque Statistics
===============================================================

Jobs Stats
   Processed Jobs : 3
   Failed Jobs    : 0


Workers Stats
   Workers count : 1
    localhost:39290:default
       - Started on     : Tue Dec 18 01:35:08 JST 2012
       - Processed Jobs : 1
       - Failed Jobs    : 0

以上、CakePHPにてジョブキューを処理するプラグインについて説明しましたがいかがだったでしょうか。Redisを別サーバーで立ちあげたい場合など、より詳しい使い方については公式サイト Cake Resque に記載されていますので参照してください。