diff --git a/src/TicketingServiceProvider.php b/src/TicketingServiceProvider.php index c50c6e6..1673d34 100644 --- a/src/TicketingServiceProvider.php +++ b/src/TicketingServiceProvider.php @@ -2,6 +2,7 @@ namespace Dashboard\Ticketing; +use Illuminate\Console\Scheduling\Schedule; use Illuminate\Support\ServiceProvider; class TicketingServiceProvider extends ServiceProvider @@ -29,5 +30,46 @@ class TicketingServiceProvider extends ServiceProvider \Dashboard\Ticketing\Console\Commands\RepairMergedTickets::class, ]); } + + $this->scheduleAutoClose(); + } + + /** + * THE NIGHTLY AUTO-CLOSE IS SCHEDULED HERE, BESIDE THE COMMAND IT NAMES + * ([central-ticketing] #2980, a spawn of [dashboard-shell] #2965). + * + * It used to be one line in the shell's routes/console.php — a file that + * names commands other repositories define. On 2026-09-26 01:10 PDT that + * arrangement cost production a php process a day whose entire output was + * *Command "admissions:remind-unconfirmed-links" is not defined*, exit 1: a + * schedule had reached a box nine and a half hours ahead of the code it + * scheduled, and nothing an operator could press would have fixed it, + * because the code was not there to fix. + * + * Registered from this provider, that is not expressible. The event exists + * on exactly the boxes where `AutoCloseTickets` is registered above, + * because the same `boot()` does both and both arrive in the same commit. + * A shell without central-ticketing simply has no such row in + * `schedule:list`, rather than a nightly failure about one. + * + * ── THE MINUTE IS STILL THE SHELL'S TO DECIDE ────────────────────────── + * + * `ScheduleStagger` is the one place a start time is chosen, and that is + * the whole point of it: a bare `->daily()` is 00:00:00, where every hourly + * and every quarter-hourly task on the platform already boots its own PHP + * inside the scheduler's one cgroup ([dashboard-shell] #1910). A time typed + * in this repository could not know that. Asking `dailyAt()` keeps this job + * at 00:12 — exactly where routes/console.php had it — and keeps the shell's + * map the single account of the night even for a job it no longer schedules. + * + * No `withoutOverlapping()`, and deliberately not added here: the shell's + * line carried none, and a lock is a behaviour change rather than a move. + */ + private function scheduleAutoClose(): void + { + $this->callAfterResolving(Schedule::class, function (Schedule $schedule) { + $schedule->command('ticketing:auto-close') + ->dailyAt(\App\Support\Ops\ScheduleStagger::dailyAt('ticketing:auto-close')); + }); } }