From ce6e8b48e00258888ddf11fdf718cf7fbb47a6b5 Mon Sep 17 00:00:00 2001 From: Kevin Adametz Date: Tue, 6 Oct 2026 16:11:58 +0000 Subject: [PATCH] =?UTF-8?q?deploy:=20Worker-Pr=C3=BCfung=20am=20Ende=20von?= =?UTF-8?q?=20deploy.sh=20=E2=80=94=20monitoring:queue-probe=20stellt=20ei?= =?UTF-8?q?nen=20Test-Job=20ein=20und=20wartet=20bis=2060=20s;=20ohne=20Wo?= =?UTF-8?q?rker=20Exit=203=20mit=20Hinweis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Anlass 06.10.2026: Nach dem Deploy von v1.3.0 hat queue:restart den Worker beendet, Supervisor lief nicht, über eine Stunde blieben KI-Prüfungen und Mails liegen, ohne dass es auffiel. Co-Authored-By: Claude Opus 5.5 --- app/Console/Commands/MonitoringQueueProbe.php | 51 +++++++++++++++++++ app/Jobs/Monitoring/QueueProbe.php | 31 +++++++++++ dev/betrieb/deploy.sh | 15 ++++++ tests/Feature/Monitoring/QueueProbeTest.php | 39 ++++++++++++++ 4 files changed, 136 insertions(+) create mode 100644 app/Console/Commands/MonitoringQueueProbe.php create mode 100644 app/Jobs/Monitoring/QueueProbe.php create mode 100644 tests/Feature/Monitoring/QueueProbeTest.php diff --git a/app/Console/Commands/MonitoringQueueProbe.php b/app/Console/Commands/MonitoringQueueProbe.php new file mode 100644 index 00000000..37f20156 --- /dev/null +++ b/app/Console/Commands/MonitoringQueueProbe.php @@ -0,0 +1,51 @@ +option('wait')); + + QueueProbe::dispatch($token); + + for ($second = 0; $second <= $wait; $second++) { + if (Cache::has(QueueProbe::cacheKey($token))) { + Cache::forget(QueueProbe::cacheKey($token)); + $this->info(sprintf('Queue-Worker läuft (Test-Job nach %d s abgeholt).', $second)); + + return self::SUCCESS; + } + + if ($second < $wait) { + Sleep::for(1)->second(); + } + } + + $this->error(sprintf('Kein Queue-Worker hat den Test-Job innerhalb von %d s abgeholt.', $wait)); + $this->line('Worker in Ploi prüfen (Site ▸ Queue). Läuft Supervisor? Notfalls: nohup php artisan queue:work database --queue=classification,default --tries=3 --max-time=3600 &'); + + return self::FAILURE; + } +} diff --git a/app/Jobs/Monitoring/QueueProbe.php b/app/Jobs/Monitoring/QueueProbe.php new file mode 100644 index 00000000..4d253d8b --- /dev/null +++ b/app/Jobs/Monitoring/QueueProbe.php @@ -0,0 +1,31 @@ +token), now()->toIso8601String(), now()->addMinutes(10)); + } +} diff --git a/dev/betrieb/deploy.sh b/dev/betrieb/deploy.sh index 4bb0cd3e..af2d4c9b 100755 --- a/dev/betrieb/deploy.sh +++ b/dev/betrieb/deploy.sh @@ -18,6 +18,9 @@ # (Standard: echo "" | sudo -S service php8.4-fpm reload). # Leer setzen, wenn FPM von Hand in Ploi neu geladen wird. # +# Exit-Codes: 0 fertig, 1 abgebrochen (siehe Ausgabe), 2 falscher Aufruf, +# 3 live, aber kein Queue-Worker hat den Test-Job abgeholt. +# # Rollback: dasselbe Skript mit dem vorherigen Tag. set -euo pipefail @@ -141,5 +144,17 @@ step "Version" php artisan about --only=pressekonto trap - ERR + +# Läuft ein Worker? `queue:restart` oben beendet ihn; neu starten muss ihn +# Supervisor. Am 06.10.2026 lief Supervisor nicht, und nach dem Deploy von +# v1.3.0 blieben KI-Prüfungen und Mails über eine Stunde liegen. +step "Queue-Worker" +if ! php artisan monitoring:queue-probe --wait=60; then + echo + echo "!! Deploy $tag ist live, aber KEIN Queue-Worker läuft." >&2 + echo "!! Jetzt in Ploi Site ▸ Queue (und Supervisor) prüfen — sonst bleiben Prüfungen und Mails liegen." >&2 + exit 3 +fi + echo echo "Deploy $tag fertig (vorher $previous). Weiter mit den Prüfungen in dev/betrieb/git-deploy.md, Abschnitt D." diff --git a/tests/Feature/Monitoring/QueueProbeTest.php b/tests/Feature/Monitoring/QueueProbeTest.php new file mode 100644 index 00000000..a0e4b32f --- /dev/null +++ b/tests/Feature/Monitoring/QueueProbeTest.php @@ -0,0 +1,39 @@ +artisan('monitoring:queue-probe', ['--wait' => 30]) + ->expectsOutputToContain('Queue-Worker läuft (Test-Job nach 0 s abgeholt).') + ->assertSuccessful(); + + Sleep::assertSleptTimes(0); +}); + +test('without a worker the probe fails after the waiting time with a hint', function () { + Sleep::fake(); + Queue::fake(); + + $this->artisan('monitoring:queue-probe', ['--wait' => 5]) + ->expectsOutputToContain('Kein Queue-Worker hat den Test-Job innerhalb von 5 s abgeholt.') + ->expectsOutputToContain('Worker in Ploi prüfen') + ->assertFailed(); + + Queue::assertPushed(QueueProbe::class, fn (QueueProbe $job): bool => $job->queue === null); + Sleep::assertSleptTimes(5); +}); + +test('the probe job only acknowledges its own token', function () { + (new QueueProbe('abc'))->handle(); + + expect(cache()->has(QueueProbe::cacheKey('abc')))->toBeTrue() + ->and(cache()->has(QueueProbe::cacheKey('xyz')))->toBeFalse(); +});