Files
termanager2/app/Jobs/RigeneraPiantine.php

100 lines
3.2 KiB
PHP

<?php
namespace App\Jobs;
use App\Models\TerritorioMappa;
use App\Services\Piantine\PiantinaPdfService;
use App\Services\Piantine\PiantinaRenderer;
use App\Services\Piantine\PiantineOperationState;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
/**
* Rigenerazione massiva delle piantine: per ogni territorio con un poligono
* disegnato rigenera l'immagine dal renderer e, a richiesta, ricompone e
* sostituisce anche il PDF (versione precedente archiviata nello storico).
*
* Un territorio che fallisce non ferma gli altri: viene contato e loggato,
* l'esito finale riepiloga quanti sono andati a buon fine.
*/
class RigeneraPiantine implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public int $tries = 1;
// Rendering + PDF per decine di territori: largo ma non illimitato, per
// non lasciare il worker inchiodato se il renderer smette di rispondere.
public int $timeout = 5400;
public function __construct(
public string $operationId,
public bool $anchePdf,
) {
}
public function handle(
PiantineOperationState $state,
PiantinaRenderer $renderer,
PiantinaPdfService $pdfService,
): void {
$state->markRunning($this->operationId);
$state->log($this->operationId, 'Rigenerazione avviata.');
$mappe = TerritorioMappa::with('territorio')->orderBy('territorio_id')->get();
$processed = 0;
$falliti = 0;
foreach ($mappe as $mappa) {
$territorio = $mappa->territorio;
$etichetta = $territorio ? "territorio {$territorio->numero}" : "mappa #{$mappa->id}";
try {
if (! $territorio) {
throw new \RuntimeException('il territorio associato non esiste più');
}
$renderer->render($mappa);
$state->log($this->operationId, "Immagine rigenerata per {$etichetta}.");
if ($this->anchePdf) {
$pdfService->sostituisci($territorio, $mappa, 'rigenerazione');
$state->log($this->operationId, "PDF sostituito per {$etichetta}.");
}
} catch (\Throwable $e) {
$falliti++;
$state->log($this->operationId, "[ERRORE] {$etichetta}: {$e->getMessage()}");
}
$processed++;
$state->avanza($this->operationId, $processed, $falliti);
}
$state->log(
$this->operationId,
'Rigenerazione conclusa: ' . ($processed - $falliti) . ' riuscite, ' . $falliti . ' fallite.'
);
$state->markCompleted($this->operationId);
}
/**
* Chiude l'operazione quando il job muore fuori da handle() (timeout,
* worker terminato): senza, la pagina resterebbe a interrogare per sempre
* uno stato "running".
*/
public function failed(?\Throwable $e): void
{
app(PiantineOperationState::class)->markFailed(
$this->operationId,
$e?->getMessage() ?? 'Job interrotto in modo inatteso.'
);
}
}