deploy: Worker-Prüfung am Ende von deploy.sh — monitoring:queue-probe stellt einen Test-Job ein und wartet bis 60 s; ohne Worker Exit 3 mit Hinweis

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 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-10-06 16:11:58 +00:00
parent 2c25eea045
commit c223daa563
4 changed files with 136 additions and 0 deletions

View file

@ -0,0 +1,51 @@
<?php
namespace App\Console\Commands;
use App\Jobs\Monitoring\QueueProbe;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Sleep;
use Illuminate\Support\Str;
/**
* Prüft, ob ein Queue-Worker läuft: stellt einen Test-Job ein und wartet,
* bis er abgeholt ist (Aufruf am Ende von dev/betrieb/deploy.sh).
*
* Anlass 06.10.2026: Nach dem Deploy von v1.3.0 hat `queue:restart` den
* Worker beendet, Supervisor lief nicht und startete ihn nicht neu — über
* eine Stunde blieben KI-Prüfungen und Mails liegen, ohne dass es auffiel.
*/
class MonitoringQueueProbe extends Command
{
protected $signature = 'monitoring:queue-probe
{--wait=60 : Sekunden, die auf den Worker gewartet wird}';
protected $description = 'Prüft mit einem Test-Job, ob ein Queue-Worker läuft.';
public function handle(): int
{
$token = Str::random(16);
$wait = max(0, (int) $this->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;
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Jobs\Monitoring;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Cache;
/**
* Test-Job für `monitoring:queue-probe`: tut nichts außer zu quittieren,
* dass ein Worker ihn abgeholt hat. Läuft auf `default` — der Worker hört
* auf `classification,default`.
*/
class QueueProbe implements ShouldQueue
{
use Queueable;
public int $tries = 1;
public function __construct(public string $token) {}
public static function cacheKey(string $token): string
{
return 'monitoring:queue-probe:'.$token;
}
public function handle(): void
{
Cache::put(self::cacheKey($this->token), now()->toIso8601String(), now()->addMinutes(10));
}
}