The scheduler that never ran
19 August 2026 · 9 min read postmortem laravel
Two production apps had a scheduler configured, a cron entry firing every minute, and a log that said everything was fine. Neither had run a single scheduled task in months.
The symptom
Rank checks stopped updating. Not erroring — updating. The dashboard showed data from weeks ago and no exception anywhere. Every obvious thing checked out: the cron entry existed in hPanel, schedule:run executed on the minute, the log file grew.
What was actually happening
Laravel's Schedule::command() does not call your command. It builds a shell command and spawns a new PHP process to run it.
// this is a subprocess, not a method call
Schedule::command('rank:check')->hourly();
On shared hosting, proc_open, exec and shell_exec are disabled. The spawn silently fails. schedule:run exits zero, reports it dispatched the task, and nothing ever runs.
The fix
// runs in-process — no proc_open, no subprocess
Schedule::call(fn () => Artisan::call('rank:check'))->hourly();
That works, but it hides failures the same way. So the second half of the fix was a doctor command that proves the thing rather than asserting it.
The lesson worth keeping
A green log is not evidence. The scheduler reported success at every layer it could see, because from its own point of view it had succeeded — it handed the work to a process that never existed.
Anything whose only proof of life is its own log line needs a second, independent check.