PHP

php-resque を試す

More than 3 years have passed since last update.


php-resque を試す

redis を使ったジョブキュー&ワーカーの仕組みとしては github が使っている resque が有名です。PHP で同じようなものが欲しかったので調べていたら php-resque というものを見つけたので試してみました。


インストール

redis のインストールは省きます。

php-resque は composer でインストールします。今回は github の HEAD を試しました。

{

"require": {
"chrisboulton/php-resque": "dev-master#610c4dcdbf3e7e5856f694384f3160db94850d1f"
}
}

php-resque は pcntl 系の関数を使うので、pcntl が無効にされていると期待した動作をしてくれず、エラーにもならずめんどくさいことになるので、php.ini で disabled_functions に pcntl が無効にされていたりしないことを確認してください。


ジョブの登録

php-resque のジョブ登録は Resque::enqueue で行えます。

<?php

// enqueue.php
require 'vendor/autoload.php';

Resque::setBackend('localhost:6379');

$args = array('x' => 12, 'y' => 31);
Resque::enqueue('multiply', 'Multiplier', $args);

Resque::queue の引数は


  1. ジョブキューの名前

  2. ジョブを実行するクラス名

  3. 引数

です。引数には配列を渡します。

ここでは multiply キューにつっこんだジョブを Multiplier クラスに処理してもらおうとしています。


ワーカーの定義

ワーカーはごく普通のクラスとして定義します。::perform が処理の中心です。setUptearDown で前処理・後処理を追加することもできます。

<?php

// Multiplier.php
class Multiplier
{

public function setUp()
{
}

public function perform()
{
$x = $this->args['x'];
$y = $this->args['y'];
sleep(1); // テストのため重い処理っぽい雰囲気を出す
$result = $x * $y;
echo "Multiply: x * y = $result" . PHP_EOL;
}

public function tearDown()
{
}

}


ワーカーの起動と設定

ワーカーの起動は ./vendor/bin/resque を叩くだけです。動きは環境変数で変えることができます。

使える環境変数の一覧です。


  • QUEUE

  • REDIS_BACKEND

  • REDIS_BACKEND_DB

  • LOGGING

  • VERBOSE

  • VVERBOSE

  • APP_INCLUDE

  • BLOCKING

  • INTERVAL

  • COUNT

  • PREFIX

  • PIDFILE

いくつか重要と思うものを説明します。


QUEUE

ジョブキューの名前を指定します。複数のキューを監視する場合はカンマ区切りで指定します。

全てのジョブキューを監視するときは * を指定します。

複数のジョブキューを指定した場合、優先度は前のキューのほうが高くなります。


INTERVAL, BLOCKING

Redis をキューとして使用する場合は LPOP コマンドを使ってキューをポーリングする方法と、BLPOP コマンドを使ってジョブがやってくるまでブロックする方法があります。

php-resque ではデフォルトでは LPOP を使用します。BLOCKING=1 を指定すると BLPOP を使用するようになります。

LPOP するか BLPOP するかで INTERVAL の意味は変わります。LPOP する場合は INTERVAL はポーリングの間隔(秒)ですが、BLPOP する場合はタイムアウト(秒)に変わります。


PIDFILE

ワーカーの PID ファイルを作成するパスを指定します。


COUNT

起動するワーカーの数を指定します。例えば COUNT=4 とすると 4 つのワーカープロセスが起動します。

複数のワーカーを起動する場合、前述の PIDFILE の設定は無効となります。


サンプル


multiply キューに登録されたジョブを 1 秒おきにポーリングして処理する

QUEUE=multiply INTERVAL=1 APP_INCLUDE=Multiplier.php ./vendor/bin/resque


multiply キューに登録されたジョブをタイムアウト 5 秒で BLPOP して処理する

QUEUE=multiply BLOCKING=1 INTERVAL=5 APP_INCLUDE=Multiplier.php ./vendor/bin/resque


ワーカーを監視する

php-resque では worker を束ねる master のようなプロセスは存在しません。worker が死んだらそれまでです。

COUNT の設定は利用せず、PIDFILE の設定を利用し、monit などで監視するのが良さそうです。


ジョブの進行状況を確認する

Resque::enqueue の第 4 引数を true に設定すると、戻り値の token を利用してジョブの進行状況を監視できます。

こんな感じです。

<?php

// enqueue2.php
require 'vendor/autoload.php';

Resque::setBackend('localhost:6379');

$args = array('x' => 12, 'y' => 31);
$tracking = true;
$token = Resque::enqueue('multiply', 'Multiplier', $args, $tracking);
echo "job id: $token" . PHP_EOL;

while (true) {
$resque_job_status = new Resque_Job_Status($token);
$status = $resque_job_status->get();
switch ($status) {
case Resque_Job_Status::STATUS_WAITING:
echo 'waiting ...' . PHP_EOL;
break;
case Resque_Job_Status::STATUS_RUNNING:
echo 'running ...' . PHP_EOL;
break;
case Resque_Job_Status::STATUS_FAILED:
echo 'failed!' . PHP_EOL;
break;
case Resque_Job_Status::STATUS_COMPLETE:
echo 'complete!' . PHP_EOL;
break;
default:
break;
}
if ($status === Resque_Job_Status::STATUS_COMPLETE || $status === Resque_Job_Status::STATUS_FAILED) {
break;
}
usleep(300 * 1000);
}


実行例

実行例を貼っておきます。

$ BLOCKING=1 QUEUE=multiply INTERVAL=10 APP_INCLUDE=Multiplier.php VVERBOSE=1 ./vendor/bin/resque

[notice] [20:26:12 2014-02-20] Starting worker takahashi-no-MacBook-Pro.local:79195:multiply
[debug] [20:26:12 2014-02-20] Registered signals
[info] [20:26:12 2014-02-20] Starting blocking with timeout of 10
[info] [20:26:23 2014-02-20] Starting blocking with timeout of 10
[info] [20:26:32 2014-02-20] Found job on multiply
[notice] [20:26:32 2014-02-20] Starting work on (Job{multiply} | ID: ec6eebf7cf41427c2a7339ab2423c6af | Multiplier | [{"x":12,"y":31}])
[info] [20:26:32 2014-02-20] Forked 79217 at 2014-02-20 20:26:32
[info] [20:26:32 2014-02-20] Processing multiply since 2014-02-20 20:26:32
Multiply: x * y = 372
[notice] [20:26:33 2014-02-20] (Job{multiply} | ID: ec6eebf7cf41427c2a7339ab2423c6af | Multiplier | [{"x":12,"y":31}]) has finished

$ php enqueue2.php

job id: ec6eebf7cf41427c2a7339ab2423c6af
running ...
running ...
running ...
running ...
complete!

実行しながら redis の内容を眺めると理解が深まると思うので興味があればやってみてください。


エラー時の挙動


  • redis が落ちると再度接続してくれないっぽい


感想


  • resque に比べると機能が少ないけれど最低限使える

  • ジョブが増えたときを考えると環境変数じゃなくて設定ファイルを書きたい