From dbe3677093feeaf1c34e97b99bdfe49fe28634f9 Mon Sep 17 00:00:00 2001 From: central-worker-5 Date: Mon, 28 Sep 2026 19:27:56 -0700 Subject: [PATCH] #3144: this app's scheduled jobs run on the school's clock, not the server's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `dailyAt()`/`weeklyOn()` with no `->timezone()` are read against `config('app.timezone')`, which is UTC on every box this platform runs on, so every line here that pinned an hour was running seven or eight hours early. Each now names \App\Support\Timezone::organisation(), the one place the school's own zone is decided. organisation() and not current(): there is no signed-in user on a scheduler tick, so the two agreed only by falling through, and stop agreeing the moment anything resolves the schedule inside a request. It reads a setting and cannot throw — it catches its own failure and falls back to America/Vancouver. The shell half ([dashboard-shell] #3144) carries the guard that keeps this true: it walks the REAL schedule, so a snapins.lock bump that brings back an unclocked line reddens the shell's run. --- src/TicketingServiceProvider.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/TicketingServiceProvider.php b/src/TicketingServiceProvider.php index 1673d34..1f52c25 100644 --- a/src/TicketingServiceProvider.php +++ b/src/TicketingServiceProvider.php @@ -69,6 +69,12 @@ class TicketingServiceProvider extends ServiceProvider { $this->callAfterResolving(Schedule::class, function (Schedule $schedule) { $schedule->command('ticketing:auto-close') + // …AND THE CLOCK IS THE SCHOOL'S ([dashboard-shell] #3144). + // ScheduleStagger decides the MINUTE; `dailyAt()` on its own is + // read against config('app.timezone'), which is UTC on every box + // here — so 00:12 was landing at 17:12 the previous afternoon, + // i.e. the nightly sweep ran in the middle of the school day. + ->timezone(\App\Support\Timezone::organisation()) ->dailyAt(\App\Support\Ops\ScheduleStagger::dailyAt('ticketing:auto-close')); }); }