CluPilotCloud/app/Console/Commands/EndDueServices.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;
}
}