CluPilotCloud/app/Jobs/RunCatalogueSync.php

74 lines
2.6 KiB
PHP

<?php
namespace App\Jobs;
use App\Services\Billing\CatalogueSyncStatus;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Artisan;
use Throwable;
/**
* Run `stripe:sync-catalogue` from the console, on the queue.
*
* Queued rather than done inside the Livewire call that asked for it: the
* command talks to Stripe, creates a Product per plan family and a Price per
* priced row on both tax treatments, and a first run on a full catalogue is
* seconds to minutes of network. A synchronous button would hold the request
* open for all of it and hand the operator a gateway timeout for an answer,
* with the run still going somewhere behind it.
*
* No agent, unlike UpdateChannel's requests: this needs nothing root can do and
* nothing outside the container. It is an artisan command this very application
* already ships, run by this very application's worker.
*
* NOT retried. Every other job here backs off and tries again; this one must
* not. The command is idempotent about Stripe objects, but a re-run after a
* failure would overwrite the recorded output with a second attempt's — and
* the output is the whole point: the refusal that names three columns to clear
* would be replaced by whatever the retry happened to say. An operator pressing
* the button again is the retry, and they will have read the first answer.
*/
class RunCatalogueSync implements ShouldQueue
{
use Queueable;
public int $tries = 1;
public function __construct(
public bool $dryRun,
public string $by,
) {}
public function handle(): void
{
$status = app(CatalogueSyncStatus::class);
try {
$exit = Artisan::call('stripe:sync-catalogue', $this->dryRun ? ['--dry-run' => true] : []);
$output = Artisan::output();
} catch (Throwable $e) {
// A throw is an outcome too, and it has to reach the page. Left
// uncaught this would be a failed job in a table nobody on this
// page can see, under a "sync running" note that never resolves.
$status->record(
ok: false,
dryRun: $this->dryRun,
output: $e->getMessage(),
by: $this->by,
);
return;
}
$status->record(
ok: $exit === 0,
dryRun: $this->dryRun,
// Whole and unedited — see CatalogueSyncStatus. The command's own
// refusals are instructions, not statuses.
output: trim($output),
by: $this->by,
);
}
}