PHP(Laravel)で非同期処理を実行する

もう少しサクッとやりたかった。
用途としては即レスポンスを返して裏でログ登録をしたいときなど。




コマンド呼び出して非同期に実行する




exec('nohup php -c xxxx.php  > /dev/null &');

phpを実行する処理を行う。
簡単だがライブラリのパス周りの解決方法がわからなかった。



Laravelのキューを使用する



https://readouble.com/laravel/5.7/ja/queues.html
キューを登録するためのテーブルが必要。

php artisan queue:table
php artisan migrate

ジョブ作成

php artisan make:job JobTest

ShouldQueueを継承したクラスがapp/Jobs以下に作成される。

class JobTest implements ShouldQueue
{
    /**
     * 最大試行回数
     *
     * @var int
     */
    public $tries = 1;
   
    protected $id;
    protected $text;
    
    public function __construct($map)
    {
        $this->id = $map['id'];
        $this->text = $map['text'];
    }
    public function handle()
    {
     // ログを追加する
     addlog($this->id, $this->text)
    }
}

デフォルトだと失敗したときに再施行するので$triesを1に設定する。
コンストラクタには0~1つの引数を渡せる。複数渡したい場合クラスか連想配列を渡す。
キュー実行時handleメソッドが実行される。


ジョブ呼び出し処理

JobTest::dispatch(array('id'=>"0001", 'text'=>"test message"));

JobTestクラスのコンストラクタが呼び出された後handleメソッドが実行される。
引数は一つなので手っ取り早く実装したいなら連想配列を渡す。


.env修正
jobの登録先を設定する。DBならほぼ使用しているはずなので手っ取り早いか。

QUEUE_DRIVER=database


以上で実装は完了だが一つ問題がありキューを処理するためには
php artisan queue:work
でワーカーを立ち上げなければいけない。
本番で使用する場合再起動時にコマンドが実行されるようにしないといけない。
やりたいことはこういうことではない。

そこでキューを登録した後以下のスニペットを追記する。
JobTest::dispatch(array('id'=>"0001", 'text'=>"test message"));
$cmd = "nohup php " . base_path() . "/artisan queue:work --once > /dev/null &";
exec($cmd);

これで1回のみ非同期ジョブを処理することができる。
終了時にはプロセスがkillされる。

ただ呼び出されるたびにプロセスが立ち上がるのは少々気になる。
ジョブが多すぎる場合問題が出るかもしれない。

2019年9月11日水曜日