Closed akagane99 closed 3 years ago
キューテーブルを作成するコマンドを実行したところ、下記エラーが発生。
CreateJobsTable
クラスが既に存在している、との事。
下記にあった。
php artisan queue:table
で作成されたDBテーブルをutf8mb4対応したもの。php artisan queue:failed-table
で作成されたDBテーブルそのままjobクラスも下記にあり。 https://github.com/opensource-workshop/connect-cms/tree/master/app/Jobs
作業途中か不明のため、要確認。手を付けられず。 既に掲示板に対応している、とコミットコメントあるけど、真偽不明。 ⇒ 確認しました。掲示板も含みメールキューは動いてない。jobsは掲示板で直接呼び出して使っているらしい。 ⇒⇒ プログラムを調査する。
>php artisan queue:table
InvalidArgumentException : A CreateJobsTable class already exists.
at C:\projects\connect-cms\htdocs\connect-cms\vendor\laravel\framework\src\Illuminate\Database\Migrations\MigrationCreator.php:90
86| }
87| }
88|
89| if (class_exists($className = $this->getClassName($name))) {
> 90| throw new InvalidArgumentException("A {$className} class already exists.");
91| }
92| }
93|
94| /**
Exception trace:
1 Illuminate\Database\Migrations\MigrationCreator::ensureMigrationDoesntAlreadyExist("create_jobs_table", "C:\projects\connect-cms\htdocs\connect-cms\database/migrations")
C:\projects\connect-cms\htdocs\connect-cms\vendor\laravel\framework\src\Illuminate\Database\Migrations\MigrationCreator.php:50
2 Illuminate\Database\Migrations\MigrationCreator::create("create_jobs_table", "C:\projects\connect-cms\htdocs\connect-cms\database/migrations")
C:\projects\connect-cms\htdocs\connect-cms\vendor\laravel\framework\src\Illuminate\Queue\Console\TableCommand.php:80
Please use the argument -v to see more details.
おおまかに、キューに溜めこむ部分と、キューを実行する(キューワーカ)部分に別れる。
config/queue.php
'default' => env('QUEUE_CONNECTION', 'sync'),
↓
.env
QUEUE_CONNECTION=sync
デフォルト(初期値)はsync .envで、databaseに変更する。かなぁ。
案4でいく
queue:work
コマンド実行メール送信する時だけキューワーカ動かして、送信終わったらキューワーカーを停止する。
symfonyのProcess componentで遊ぶ - Qiita
バックグラウンド実行はstart()
を指定
>>> $process = new Process(['/bin/sleep', '10'])
>>> $process->start()
php artisan queue:work --stop-when-empty
【Laravel5.7】WindowsとLinux両方で非同期処理したい - Qiita ⇒ WIN(xampp)とLinuxの処理の切り分け参考
if (strpos(PHP_OS, 'WIN') !== false) {
// Windows
} else {
// Linux
}
実行可能な PHP バイナリの検索 - プロセスコンポーネント(Symfony Docs)
use Symfony\Component\Process\PhpExecutableFinder;
$phpBinaryFinder = new PhpExecutableFinder();
$phpBinaryPath = $phpBinaryFinder->find();
// $phpBinaryPath = '/usr/local/bin/php' (the result will be different on your computer)
プロセスタイムアウト - プロセスコンポーネント(Symfony Docs) タイムアウトは非同期のため、無視されてそう
php artisan schedule:run
コマンド)必要。
⇒ Laravelのタスクスケジュールに、例えばqueue:restart
, queue:work --tries=3
コマンドを実行するタスクスケジュールを作成して、cronから実行する。php artisan schedule:run
コマンド)の1行追加が必要。微妙だったので廃案
・~~\Symfony\Component\Process\Process を使ってコマンドの非同期実行をしているが、タイムアウト指定をしていないため、
デフォルト60秒でプロセス停止されそう。~~
⇒ 非同期コマンドだから即終了すので、プロセス停止はないだろう。
・基本的にDatabaseQueueを上書きして実装していました。
$expire = 60 となっているけど、上記と連動していないため、ここを変更しても上記で落ちそう。
⇒ 非同期でコマンド投げっぱなしのため、expireが機能するか不明。多分機能しない。
・バックグラウンドコマンドで、標準エラー出力捨ててる。
・キューが衝突する事がある?
レンタルサーバの使用はほぼ無理のため、対象外とする。
queue:work
の起動は、Supervisorで管理される。php artisan queue:restart
コマンドを実行する必要あり
⇒ updateマニュアルに追記すればOK。?
queue:work
は1対1になる必要がありそう。
⇒ Connect-CMSとqueue:work
の繋がりは、実行したartisanコマンドでConnect-CMS(Laravel)を特定できるので、それでつながっているだろう。キューワーカは長時間起動プロセスであるため、リスタートしない限りコードの変更を反映しません。 ですから、キューワーカを使用しているアプリケーションをデプロイする一番シンプルな方法は、デプロイ処理の間、ワーカをリスタートすることです。queue:restartコマンドを実行することで、全ワーカを穏やかに再起動できます。
php artisan queue:restart
failedメソッドは、ジョブがdispatchNowメソッドでディスパッチされた場合には呼び出されません。
$tries = 1
にする。【済】https://readouble.com/laravel/6.x/ja/queues.html#max-job-attempts-and-timeout
<?php
namespace App\Jobs;
class ProcessPodcast implements ShouldQueue
{
/**
* 最大試行回数
*
* @var int
*/
public $tries = 1;
}
コマンド例
php artisan queue:work --tries=3
help
>php artisan queue:work --help
Description:
Start processing jobs on the queue as a daemon
Usage:
queue:work [options] [--] [<connection>]
Arguments:
connection The name of the queue connection to work
Options:
--queue[=QUEUE] The names of the queues to work
--daemon Run the worker in daemon mode (Deprecated)
--once Only process the next job on the queue
--stop-when-empty Stop when the queue is empty
--delay[=DELAY] The number of seconds to delay failed jobs [default: "0"]
--force Force the worker to run even in maintenance mode
--memory[=MEMORY] The memory limit in megabytes [default: "128"]
--sleep[=SLEEP] Number of seconds to sleep when no job is available [default: "3"]
--timeout[=TIMEOUT] The number of seconds a child process can run [default: "60"]
--tries[=TRIES] Number of times to attempt a job before logging it failed [default: "1"]
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
--env[=ENV] The environment the command should run under
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
https://github.com/opensource-workshop/connect-cms/pull/925#issuecomment-875211029
調査結果 https://github.com/opensource-workshop/connect-cms/issues/905#issuecomment-876994341
・メール設定画面から送信方式はなくす【済】
・即時送信かスケジュール送信(バックグラウンド送信)はなくして一本化。
・即時送信かスケジュール送信かは、.envのQUEUE_CONNECTION=sync (初期値:即時送信)又は database (スケジュール送信)で切り替える。
・UserPluginBase.phpのメール送信修正【済】
・$bucket_mail->timingは見なくて、dispatch()に一本化する。
・$this->asyncQueueWork()
は、.envのQUEUE_CONNECTION=database の時のみ動かす修正入れる。
参考画面
Process は現時点では使えない事がわかったので、古式ゆかしいexecで対応見直しかなぁと。
・\Symfony\Component\Process\Process を使って非同期処理。 現在のバージョンは、Laravelの依存で、v4.4.22 だった。
・Process の非同期は、親プロセスが止まると強制停止される仕様だった。 ・Process 5.2から、親プロセスが止まっても動き続けるオプションが追加された。 ⇒ このため、現時点ではProcess を使って非同期処理は使えず、今後Laravelバージョンアップして、Process のバージョンも5.2以上になれば、利用可能な代物でした。 ⇒ 以前Linuxで非同期動いた!と思ったのは勘違いでした。💦💦 ⇒ (Process の5.2のソースだけもらってきて、オーバーライドして使う手もあるけど、対応としては微妙かなぁ)
$process = new Process(['...', '...', '...']);
// this option allows a subprocess to continue running after the main script exited
$process->setOptions(['create_new_console' => true]);
https://qiita.com/mpyw/items/15d14d920250a3b9eb5a
上記話題は、$schedule->command()
上での話で、今回はキューの話なのでちょっと扱い違うため、参考程度に読みました。
結果、問題なしでした。
※ キューワーカA, Bはどちらも --queue
オプション指定なしで起動します。(実質--queue=default
です)
attempts
reserved_at
で管理されてそう。
attempts
=0, reserved_at
=nullattempts
=1, reserved_at
=1625816xxxx ←多分時間のintid | queue | payload | attempts | reserved_at | available_at | created_at |
---|---|---|---|---|---|---|
24 | default | {"displayName":"App\Jobs\PostNoticeJob","job":"I... | 0 | NULL | 1625816897 | 1625816897 |
それぞれ別のキューを処理するため、問題なし。
⇒ 問題なし。
追加調査
タイムアウトを20秒、Jobでsleep(30);
を入れてテスト。
タイムアウト20秒
$php_artisan_command = "{$php} \"{$artisan}\" queue:work --stop-when-empty --timeout=20";
・結果、キュー1で失敗⇒ 失敗したキューは failed_jobs に入りました。 ・キュー2は処理しませんでした。 ・失敗してもログに出力なし。⇒ ログ出力するよう対応しました。
キュー1 id | connection | queue | payload | exception | failed_at |
---|---|---|---|---|---|
1 | database | default | {"displayName":"App\Jobs\PostNoticeJob","job":"I... | Illuminate\Queue\MaxAttemptsExceededException: App... | 2021-07-09 17:45:38 |
コマンドで確認
$ php artisan queue:failed
+----+------------+---------+------------------------+---------------------+
| ID | Connection | Queue | Class | Failed At |
+----+------------+---------+------------------------+---------------------+
| 1 | database | default | App\Jobs\PostNoticeJob | 2021-07-09 17:45:38 |
+----+------------+---------+------------------------+---------------------+
キュー2 id | queue | payload | attempts | reserved_at | available_at | created_at |
---|---|---|---|---|---|---|
25 | default | {"displayName":"App\Jobs\PostNoticeJob","job":"I... | 0 | NULL | 1625820318 | 1625820318 |
リトライコマンドを実行したら、failed_jobsテーブル⇒jobsテーブルに移動しました。
リトライコマンド
$ php artisan queue:retry 1
The failed job [1] has been pushed back onto the queue!
failed_jobsテーブル⇒空
(id=25) キュー2 (id=26) キュー1 ←失敗job の順
id | queue | payload | attempts | reserved_at | available_at | created_at |
---|---|---|---|---|---|---|
25 | default | {"displayName":"App\Jobs\PostNoticeJob","job":"I... | 0 | NULL | 1625820318 | 1625820318 |
26 | default | {"displayName":"App\Jobs\PostNoticeJob","job":"I... | 0 | NULL | 1625821206 | 1625821206 |
キューワーカ実行(全てのJob実行したら自動停止)
$ php artisan queue:work --stop-when-empty --timeout=3600
[2021-07-09 18:07:17][25] Processing: App\Jobs\PostNoticeJob
[2021-07-09 18:07:17][25] Processed: App\Jobs\PostNoticeJob
[2021-07-09 18:07:17][26] Processing: App\Jobs\PostNoticeJob
[2021-07-09 18:07:17][26] Processed: App\Jobs\PostNoticeJob
これで失敗Jobが再実行されました。
キューのguiは必要かなぁ?要検討 こんなんあった。
【Laravel】データベースキューを GUI で監視するためのライブラリ Laravel-Queue-Monitor の紹介 https://cpoint-lab.co.jp/article/202106/20419/
laravel6 も対応してそう。 https://github.com/romanzipp/Laravel-Queue-Monitor/blob/master/composer.json#L17
ルーティングは/manage/jobs/ に変更して別ウィンドウ表示とかかなぁ。 https://github.com/romanzipp/Laravel-Queue-Monitor#routes
デバッグの初動調査が早くなりそうですしアリかと思います。
サンキュー。月曜にでも試し実装してみる
・QUEUE_CONNECTION=sync もどす。.env ・キューのguiは入れない。
対応しました。
・キューをセット後に非同期でキューワーカを実行します。 ・キューワーカは、キューされたすべてのジョブを実行後に、プロセス停止します。
【利点】 ⇒ キューワーカが必要な時だけ非同期実行して、実行終わったら停止してもらう(キューワーカを常駐させない) ⇒⇒ これによって、キューワーカのcronでの実行不要、アプリケーション変更時のキューワーカのリスタート不要になります。
※ キューのメールJobは自動リトライしません。 (大量メール送信時の途中停止を想定して、自動リトライしない設定にしました。自動リトライすると初めの方に送った人に同じメールが飛ぶため) ※ キューワーカのタイムアウトは1時間に設定。 (非同期実行で投げっぱなしのため、万が一プロセルが動きつづけても1時間で強制停止します。1時間もかかるメール処理はないだろう想定。) ※ キューワーカのリトライ時間を1時間1分に設定(config\queue.php) (タイムアウト前にリトライ時間がくるとエラーが出るため。タイムアウトよりも後の時間に設定。) (config\queue.php の connections => [database => [retry_after]] )
・メールの「送信方式」は削除して1本化。
・.envの設定で「即時送信」か「スケジュール送信」を切り替えられる事がわかったため。
・.envのQUEUE_CONNECTION=sync は「即時送信」
・.envのQUEUE_CONNECTION=databaseは「スケジュール(バックグラウンド)送信」
参考:メールの「送信方式」
.env
###QUEUE_CONNECTION=sync
QUEUE_CONNECTION=database
https://github.com/opensource-workshop/connect-cms/issues/905#issuecomment-876994341
https://github.com/opensource-workshop/connect-cms/pull/925/files
https://github.com/opensource-workshop/connect-cms/issues/905#issuecomment-877034070
Note: The timeout feature is optimized for PHP 7.1+ and the pcntl PHP extension. (pcntl のphpエクステンション必要)
現在、このモジュールは非 Unix 環境(Windows)では動作しません。
現在のメール送信は、即時送信のみです。 Laravelのメールキューに溜めてから、別途送信できるように対応したい。
参考URL