comment(Inspiring::quote()); })->purpose('Display an inspiring quote'); // Advance every due provisioning run once a minute (runs in the scheduler service). Schedule::call(fn () => app(TickProvisioning::class)()) ->everyMinute() ->name('provisioning-tick') ->withoutOverlapping(); // Refresh the VPN peer state (handshakes, traffic) so the console does not go // stale while nobody has it open. The job itself runs on the provisioning // queue — that worker owns wg0. Schedule::job(new \App\Provisioning\Jobs\SyncVpnPeers) ->everyMinute() ->name('vpn-sync'); // Sample network counters and enforce the monthly allowance. Runs on the // provisioning queue, which is where the Proxmox credentials are usable. // Turns the monitoring column from a claim into a measurement. Without it the // console and the public status page report every instance healthy forever. Schedule::job(new \App\Provisioning\Jobs\SyncMonitoringStatus) ->everyFiveMinutes() ->withoutOverlapping(); Schedule::job(new \App\Provisioning\Jobs\CollectInstanceTraffic) ->everyFifteenMinutes() ->name('traffic-collect'); // Discard Stripe events that were held for a contract which never appeared. // Most of them never will: Stripe also delivers events for subscriptions // belonging to other environments pointed at this endpoint, and for objects // made by hand in the dashboard. A week is far longer than the moment a // checkout takes to become a contract, and short enough that the table stays // a holding area rather than a second copy of Stripe's event log. Schedule::call(fn () => \App\Models\StripePendingEvent::query() ->where('created_at', '<', now()->subWeek()) ->delete()) ->daily() ->name('stripe-pending-prune'); // Copies of invoices that never reached the archive — a NAS that was rebooting // when the invoice was issued, a mount that had gone away. Copy-on-issue is // right and is not enough: nobody opens an archive to check whether last // Tuesday is in it, so something has to go and look. // // Hourly rather than by the minute: the failure it repairs lasts as long as an // outage lasts, and a retry storm against a mount that is down helps nobody. Schedule::command('clupilot:archive-invoices') ->hourly() ->withoutOverlapping(); // Empty a handover directory of folders past their keep-by. Only where a // destination asks for it, and only folders whose name is a date this // application wrote — see the command for why it leaves everything else alone. Schedule::command('clupilot:prune-exports') ->dailyAt('03:20') ->withoutOverlapping();