75 lines
2.8 KiB
PHP
75 lines
2.8 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Actions\EndInstanceService;
|
|
use App\Models\Instance;
|
|
use Illuminate\Console\Command;
|
|
|
|
/**
|
|
* End the services whose cancellation date has arrived.
|
|
*
|
|
* ConfirmCancelPackage schedules an ending — status `cancellation_scheduled`,
|
|
* `service_ends_at` at the close of the paid period — and nothing in the
|
|
* application ever kept the appointment. That is why `TraefikWriter::remove()`
|
|
* had no caller: there was no moment at which an instance ended, so there was
|
|
* never a moment at which its router came down. Cancelled instances kept their
|
|
* hostname, their certificate and their route to a guest address the host may
|
|
* later hand to a different customer.
|
|
*
|
|
* This is the appointment. It ends nothing early: EndInstanceService::hasEnded()
|
|
* is the whole rule and a `cancellation_scheduled` instance whose date is still
|
|
* in the future is left exactly alone — see that class for why that distinction
|
|
* is the important one here.
|
|
*
|
|
* Hourly. The end of a paid term is a moment, and a sweep that ran once a night
|
|
* would hand out up to a day of service nobody decided to give — while running
|
|
* it every minute would mean a provider's bad five seconds became a failed job
|
|
* sixty times over. Nothing here is taken away that the customer did not
|
|
* themselves ask to give up, on a date they were shown, so there is no bad hour
|
|
* for it.
|
|
*/
|
|
class EndDueServices extends Command
|
|
{
|
|
protected $signature = 'clupilot:end-due-services
|
|
{--dry-run : list what would end and change nothing}';
|
|
|
|
protected $description = 'Withdraw the address of every instance whose cancellation date has passed';
|
|
|
|
public function handle(EndInstanceService $end): int
|
|
{
|
|
$dryRun = (bool) $this->option('dry-run');
|
|
$ended = 0;
|
|
|
|
// Narrowed in the query for the sake of the database, decided by
|
|
// hasEnded() for the sake of the rule: the query is an index, not a
|
|
// second opinion.
|
|
$due = Instance::query()
|
|
->with(['host', 'dnsRecords'])
|
|
->where('status', 'cancellation_scheduled')
|
|
->whereNotNull('service_ends_at')
|
|
->where('service_ends_at', '<=', now())
|
|
->cursor();
|
|
|
|
foreach ($due as $instance) {
|
|
if (! $end->hasEnded($instance)) {
|
|
continue;
|
|
}
|
|
|
|
$this->line(($dryRun ? '[dry-run] ' : '')
|
|
."{$instance->subdomain}: Laufzeit endete am "
|
|
.$instance->service_ends_at->local()->isoFormat('LLL'));
|
|
|
|
if ($dryRun || $end($instance)) {
|
|
$ended++;
|
|
}
|
|
}
|
|
|
|
$this->info($dryRun
|
|
? "Probelauf: {$ended} Dienst(e) würden beendet. Nichts wurde geändert."
|
|
: "{$ended} Dienst(e) beendet.");
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|