個人開発環境はWindows10上でXAMPP、デプロイはAzure WebAppのLinuxってかんじでやってるのですが、この環境で何が問題ってキューが動かないわけですよ。
どちらの環境でも、色々とがんばればどうにかできるのはわかってます。
でも、がんばりたくないからXAMPPなりAzureなりを使ってるわけで、キューもできるだけがんばらずにどうにかしたいところです。
コマンドコール
まずは単にArtisanコマンドを呼んでみましょう。
Artisan::call('foo:bar');
一行で終わってしまった。
これはコマンドラインからのphp artisan foo:bar
と同じで、登録したコマンドを実行するだけです。
完全に同期で、出力も全て入ってきます。
たぶん実際にはコマンド実行せず、内部的に直接呼んでるだけだと思います。
実装見てないからわかりませんが。
キューを同期実行
call
をqueue
に変えるとキュー経由の実行になります。
Artisan::queue('foo:bar');
キューがどのような手段で実行されるかはconfig/queue.php
に定義されています。
デフォルトではsync
になっていて、これはArtisan::call
と同じく同期実行です。
非同期実行
.env
設定ファイルのQUEUE_CONNECTION
をdatabase
やredis
に変更すると、Artisan::queue
が非同期で実行されるようになります。
これはどういう仕組みかというと、
・コマンドを実行しても、その時点では処理が行われず、単にデータベースに登録される。
・実はバックグラウンドでずっとキューワーカーというプロセスが走り続けている
・キューワーカーはDBの登録を見つけたら該当の処理を行う。
となっています。
問題はこのキューワーカーです。
php artisan queue:work
とコマンド一個打つだけでキューワーカーは起動するのですが、実はこれただのPHPプロセスです。
Windowsだとウィンドウを閉じたら死ぬし、そうでなくとも何かの拍子に死んだらそれっきりです。
キューワーカーが動き続けることを保証するには、プロセスモニタで監視するなり定期的に実行するなり面倒な手続きが必要です。
さて、そもそも何故Laravelでキューを使いたいのかというと、Webリクエスト時に遅い処理をバックグラウンドに回したいという理由が大半でしょう。
大半というか実際ははほぼ全てでしょう。
つまり、別にキューワーカーなど大がかりな仕組みを使わずともいいのでは?
というわけでこんなのができました。
// 非同期実行する
if (strpos(PHP_OS, 'WIN') !== false) {
// Windows
$command = 'start /B php "' . base_path('artisan') . '" foo:bar';
$fp = popen($command, 'r');
pclose($fp);
} else {
// Linux
$command = 'php "' . base_path('artisan') . '" foo:bar > /dev/null &';
exec($command);
}
非同期実行したい処理はartisanコマンドで実装しておいて、呼び出し側はコマンドラインで呼ぶだけです。
コマンドはLinuxとWindowsで異なるので分岐が必要です。
わりと簡単に非同期処理が実装できました。
これをコントローラに直接書くのはどうなんだって感じですが、ではどこに持っていくのが正解なんだろう?
定期実行
上記は、Webサーバへのリクエストを契機にバックグラウンド処理を起動させるというものでした。
毎日定時に行うバッチ処理のようなものは、これではうまくいきません。
オンプレならcrontabにphp artisan foo:bar
とか入れとけばいいですが、Windowsではcronがないのでめんどい、Azure WebAppはプログラムをzipでアップロードしたりしないといけなくてめんどいです。
どうにかならないでしょうか。
・まず定期実行したい処理を書いたコマンドを作る。
・次にそのコマンドを非同期で呼び出すコントローラを作る。
・最後にAzure Functionsから該当のコントローラを定期的にfile_get_contentsする。
かんせー。
定期的に実行させる必要があるのであれば定期的に呼び出せばいいのだ。
まとめ
これLaravel関係なくね?