The Auto Scheduler’s core loop is a Laravel `schedule:work` process — a long-running program that sits in memory and checks, roughly every minute, whether anything in the queue is due. That design works beautifully right up until the process dies, and processes die for all kinds of boring reasons: a server reboot for patching, an out-of-memory kill, a deploy script that stops the old process and forgets to restart it. On a VPS or dedicated box where you control the process lifecycle directly, the question isn’t whether `schedule:work` will eventually stop running — it’s whether something notices and brings it back before your queue backs up for hours.
That’s a process-supervision problem, and the right tool for it depends entirely on which operating system is actually running the box. On Linux, that’s systemd. On Windows, it’s Task Scheduler. They solve the same problem with genuinely different mechanics, and knowing which lever to pull — and which one not to reach for — saves a lot of wasted setup time.
What "Keeping It Alive" Actually Requires
A supervised long-running process needs three things: it has to start automatically when the server boots, it has to restart automatically if it crashes or gets killed, and ideally it needs its output captured somewhere you can actually read after the fact. `schedule:work` itself does none of this — it just runs until something stops it, the same as any other foreground process you’d start from a terminal and then lose the moment you close that terminal or the SSH session drops.
Running it directly in a terminal session is fine for testing whether the scheduler behaves correctly, but it’s not a deployment strategy — the process dies with the session, and nothing brings it back. Both systemd and Task Scheduler exist specifically to close that gap, just with very different configuration models underneath.
Systemd: The Linux Approach
On a Linux server, the standard approach is a systemd unit file — a small text configuration, typically dropped in `/etc/systemd/system/`, that describes the command to run, the user to run it as, and the restart policy to apply. The command is simply the `schedule:work` invocation pointed at your application’s artisan file, run as whatever unprivileged user owns the application via the `User=` directive rather than root, with `Restart=always` set so systemd relaunches the process immediately if it exits for any reason — crash, kill, or manual stop that wasn’t accompanied by a corresponding disable. A `WantedBy=multi-user.target` line under `[Install]` is what actually ties the unit to normal boot sequencing, and it’s the line most commonly forgotten by anyone copying a unit file from an unrelated project without reading it closely — without it, `systemctl enable` appears to succeed but the service never actually starts on the next reboot.
Once the unit is enabled with `systemctl enable`, it starts automatically on every boot without any manual intervention, and `systemctl status` gives an immediate, unambiguous answer to “is this actually running right now” — including how long it’s been up, which is itself a useful signal, since a process that’s only been running for two minutes on a server that’s been up for two weeks tells you it crashed and just got restarted recently. Logs route through `journalctl -u` followed by the unit name, which means crash output, restart events, and anything the scheduler prints all land in one queryable, timestamped stream instead of being scattered across whatever terminal happened to be open when something broke — and unlike a plain log file, `journalctl` lets you filter by time range directly, which matters when you’re trying to reconstruct exactly when an outage started.
Task Scheduler: The Windows Approach
Windows doesn’t have a direct systemd equivalent, and Task Scheduler — built for firing scheduled tasks at specific times, not for supervising a continuously running process — is a slightly awkward fit that still works if configured correctly. The trigger you want isn’t a fixed time; it’s “at system startup,” paired with a task action that launches the `schedule:work` command. Task Scheduler’s own “restart on failure” setting can then be configured with a retry count and interval, which gives you something approximating systemd’s `Restart=always`, though it’s coarser — Task Scheduler checks whether the task’s process is still alive at defined intervals rather than reacting the instant the process dies.
The setting most commonly missed here is “run whether user is logged on or not,” combined with running under a dedicated service account rather than an interactive user’s session — without it, the task quietly stops the moment nobody’s logged into the console, which defeats the entire point on a server that’s meant to run unattended. It’s easy to configure this correctly in a test session where you’re logged in the whole time and never notice the gap until the server reboots unattended weeks later and the scheduler doesn’t come back with it.
The GUI wizard is the usual entry point, but the same task can be created or updated from the command line with `schtasks.exe /create`, which is worth knowing if you ever need to script the setup across more than one machine or reproduce a working configuration exactly rather than re-clicking through the wizard and risking a missed checkbox. The task’s history pane — disabled by default on many Windows installs — is also worth explicitly enabling, since without it a failed restart attempt leaves no trace anywhere obvious, and you’re left inferring a problem only from the queue backing up rather than seeing the actual restart failure recorded.
The Failure Mode Each One Is Actually Protecting Against
Systemd’s restart policy is mainly protecting against crashes and OOM kills — the process dying unexpectedly while the machine itself stays up. Task Scheduler’s startup trigger is mainly protecting against reboots — the whole machine coming back up after maintenance or a power event and needing every long-running service re-launched from scratch. Both platforms need to protect against both failure modes, but the emphasis in default configuration tends to differ, which is why it’s worth explicitly checking both boxes — restart-on-crash and start-on-boot — rather than assuming one implies the other.
On Linux specifically, it’s worth pairing `Restart=always` with a `RestartSec` value of at least a few seconds rather than an instant retry — a process that’s crashing because of a genuine configuration problem will otherwise restart in a tight loop, hammering the CPU and flooding the journal, rather than giving you a clean, readable failure to diagnose.
Verifying the Setup Actually Works
Configuring the supervisor is only half the job; the other half is proving it recovers correctly, which means deliberately killing the process and watching what happens next rather than trusting the configuration on faith. On Linux, `kill -9` against the `schedule:work` process ID should produce a fresh process within a couple of seconds, visible in `systemctl status` with a new start time and a low uptime. On Windows, ending the task’s process from Task Manager should trigger Task Scheduler’s restart action within whatever interval you configured, visible in the task’s history pane.
It’s also worth testing the boot case specifically, not just the crash case — a full reboot of the server, followed by checking whether the scheduler is running without anyone touching the console. This is the scenario most commonly assumed to work and least commonly actually tested, and it’s exactly the scenario that tends to surface the “run whether user is logged on or not” gap on Windows, or a systemd unit that was started manually once but never actually enabled for boot.
When You Don't Need Either of These
All of this supervision machinery is specifically for environments where `schedule:work` runs as a persistent process — a VPS, a dedicated server, a container you manage yourself. On shared hosting environments that don’t allow long-running processes at all, the Auto Scheduler falls back to plain OS cron instead, invoking the scheduler’s check on a fixed interval rather than keeping a process alive continuously. That’s a genuinely different deployment mode with its own considerations, not a lighter version of what’s described here, and reaching for a systemd unit or a Task Scheduler entry in an environment where the host actively kills long-running processes is a wasted effort — the host will kill it again regardless of how well you’ve configured the restart policy.
Log Rotation and Long-Term Housekeeping
Neither supervisor keeps logs forever by default, and it’s worth knowing where each one’s ceiling is rather than discovering it during an incident. `journalctl`’s storage is bounded by systemd-journald’s own retention settings — typically a size cap on `/var/log/journal` — so on a long-lived server it’s worth checking that the cap is generous enough to cover at least a few weeks of scheduler activity, since a tightly capped journal will happily rotate out the exact window you need when you’re trying to reconstruct an outage that started ten days ago.
Task Scheduler’s history pane has its own limits, and the underlying Windows Event Log that backs it is also size-capped and rotates on its own schedule, independent of anything you’ve configured for the task itself. Neither of these is usually worth changing preemptively, but both are worth knowing about before the day you actually need three-week-old restart history and find it’s already gone.
Choosing Between the Two When You Have a Choice
If you’re provisioning a new server specifically to run the scheduler and get to pick the OS, Linux with systemd is the simpler, more transparent option — the configuration is a single readable text file, the status and logs are unified under one command, and the restart behavior is precise down to the second. Task Scheduler is a perfectly workable fallback when Windows is already the fixed constraint — an existing Windows server, a team more comfortable administering Windows infrastructure — but it’s rarely the platform anyone would choose from scratch purely for running a background worker process.
Either way, the underlying goal is identical: the scheduler’s every-minute check for due posts needs a process that’s actually alive to perform that check, and the OS-level supervisor is what stands between “alive most of the time” and “alive continuously, with automatic recovery from the failures that would otherwise silently stall your entire queue.”
Where to Go Next
Process supervision is the infrastructure layer underneath everything else the scheduler does — queueing, cadence, workflow chaining all assume the underlying process is actually running. For the broader picture of how those pieces fit together, see Scheduling and Workflow Automation: The Complete Guide.