こんにちは。ビンゴ細羽です。
FuelPHPで非同期処理(JobQueue)を実現するパッケージがこれといって見当たらなかったので、fuel-jobqueueパッケージを作ってみました。
まだテストが全く書けていなかったり、エラー処理が怪しかったり、Loggingが不十分だったりしますが、
とりあえず使える形にはなったので公開しておきます。
仕組み
Queueのバックエンドとして、今回はbeanstalkdを利用しました。
なお、バックエンドに応じたConnector/Queue/Jobインターフェースの実装を追加することで、
他のバックエンドにも対応できる(はず)なので、今後時間があればAmazon SQSやphp-resqueの実装を追加していきたい。
基本的な作りとしては、Laravel PHP Queueを参考にしました。
使い方
READMEの翻訳版です。。
1. composer
composerに対応しています。
1 2 3 4 5 |
"require": { ... "hosopy/fuel-jobqueue": "dev-master", ... }, |
1 |
$ php composer.phar update |
2. Packageの読み込み設定
fuel/app/config/config.php でパッケージの読み込み設定を追加します。
※もちろん、コード内での動的な読み込みもOKです。
1 2 3 4 |
'always_load' => array( 'packages' => array( 'fuel-jobqueue', ... |
3. 設定 (jobqueue.php)
デフォルトの設定ファイルをappにコピーします。
1 |
$ cp fuel/packages/fuel-jobqueue/config/jobqueue.php fuel/app/config |
もしくは、FUEL_ENVに応じた設定として保存してもOKです。
1 |
$ cp fuel/packages/fuel-jobqueue/config/jobqueue.php fuel/app/${FUEL_ENV}config |
基本的にデフォルトの設定で良いと思いますが、beanstalkd関連で変更したい項目があれば変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
return array( // default connection name 'default' => 'default_connection', 'connections' => array( 'default_connection' => array( 'driver' => 'beanstalkd', 'host' => '127.0.0.1', 'port' => '11300', 'queue' => 'jobqueue', ), ), ); |
4. beanstalkdのインストール・起動
Queueのバックエンドとして利用するbeanstalkdをインストールします。
1 2 3 4 5 6 7 8 9 10 |
## Mac (homebrew) $ brew install beanstalkd # 自動起動設定しない場合は手動で起動 $ beanstalkd ## Linux (Ubuntu) $ sudo apt-get install beanstalkd # インストール後は自動で起動されているはず。 # 起動されていなければ、/etc/init.d/beanstalkd start |
5. Jobクラスの実装
非同期で実行したい処理を記述したJobクラスを実装します。
ポイントはfire()メソッドの実装です。
1 2 3 4 5 6 7 8 9 10 11 |
<?php class Myjob { // [IMPORTANT] Requires 'fire' method as a entry point. public function fire($job, $data) { // heavy job sleep(10); \Log::info('Hello! '.$data['message']); } } |
6. Controllerの実装
実装したMyjobを、任意のControllerで生成してQueueに登録する処理を実装してみます。
1 2 3 4 5 6 7 8 9 10 11 |
class Controller_Welcome extends Controller { public function action_index() { // push a new job onto the default queue of the default connection. // 'Myjob' is a class name you have defined. \Jobqueue\Queue::push('Myjob', array('message' => 'FuelPHP')); return Response::forge(View::forge('welcome/index')); } ... |
7. Workerの起動
以上で準備は完了です。
Queueを監視するWorkerプロセスを起動します。
1 2 |
$ cd FUEL_ROOT $ php oil refine jqworker:listen --connection=default_connection --queue=jobqueue |
先ほど実装したControllerのactionを呼び出してみて、Myjobが実行されるかログを見て確認してみましょう。
番外編: Workerのデーモン化
手順7では、Workerがフォアグラウンドで起動するので、バックグラウンドで起動するためにデーモン化する方法。
pearでSystem_Daemonをインストールします。
1 |
$ sudo pear install System_Daemon |
次に、以下のコードをFUEL_ROOT 直下にdaemon.phpとして配置します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php /** * FUEL_ROOT 直下にdaemon.phpとして配置 */ require_once('System/Daemon.php'); $options = array( 'appName' => 'sample', //'authorEmail' => 'sample@example.com', 'appDescription' => 'sample', 'appDir' => dirname(__FILE__), 'sysMaxExecutionTime' => '0', 'sysMaxInputTime' => '0', //'logLocation' => dirname(__FILE__).'/daemon/daemon.log' //'appPidLocation' => dirname(__FILE__).'/daemon/daemon.pid' //'usePEARLogInstance' => $logger, //'logVerbosity' => '7', //'appRunAsUID' => 500, //'appRunAsGID' => 500, ); System_Daemon::setOptions($options); System_Daemon::start(); while (!System_Daemon::isDying()) { System_Daemon::iterate(5); system($argv[1]); } System_Daemon::stop(); ?> |
以下のコマンドでデーモンを起動します。
1 2 3 4 |
# FUEL_ENVは環境に応じて $ cd FUEL_ROOT $ sudo php daemon.php 'FUEL_ENV=production php oil refine jqworker:work --connection=default_connection --queue=jobqueue --delay=0 --memory=128 --sleep' |