CluPilotCloud/app/Jobs/ArchiveInvoice.php

71 lines
2.3 KiB
PHP

<?php
namespace App\Jobs;
use App\Models\ExportTarget;
use App\Models\Invoice;
use App\Models\InvoiceExport;
use App\Services\Billing\InvoiceArchive;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Throwable;
/**
* Put one invoice on ONE destination, and keep trying if that one is away.
*
* One job per pair rather than one per invoice: the reason for having a second
* destination is that the first can fail, and a job that writes to both would
* retry the one that worked every time the other did not — and would report a
* single outcome for two different things.
*
* Queued rather than done during the request that issued the invoice: a network
* mount can block for its whole timeout, and an invoice must not fail to be
* issued because a NAS in an office is rebooting.
*/
class ArchiveInvoice implements ShouldQueue
{
use Queueable;
public int $tries = 5;
/** A destination that is gone is usually gone for a while. */
public array $backoff = [60, 300, 900, 3600];
public function __construct(public Invoice $invoice, public ExportTarget $target) {}
public function handle(InvoiceArchive $archive): void
{
if (! $this->target->active) {
return;
}
$record = InvoiceExport::query()->firstOrNew([
'invoice_id' => $this->invoice->id,
'export_target_id' => $this->target->id,
]);
// Already there. A retry after a timeout that in fact succeeded must
// not write it a second time.
if ($record->exists && $record->exported_at !== null) {
return;
}
$record->attempts = (int) $record->attempts + 1;
$record->save();
$archive->store($this->invoice, $this->target);
$record->forceFill(['exported_at' => now(), 'error' => null])->save();
}
public function failed(?Throwable $e): void
{
// Against the pair, not the invoice: "on the office NAS, not on the
// off-site box" is the thing somebody needs to be told.
InvoiceExport::query()->updateOrCreate(
['invoice_id' => $this->invoice->id, 'export_target_id' => $this->target->id],
['error' => mb_substr((string) $e?->getMessage(), 0, 250)],
);
}
}