Product Decisions This Supports
- Whether the queue/observability roadmap can ship without a platform spend. Horizon is the reason most teams want Redis queues — the dashboard, retries, tags, and job metrics are the product value. But Laravel's docs assume Supervisor or systemd keeps the process alive. This package replaces that assumption with a cron heartbeat, which converts "we need managed hosting or an ops ticket to get queue visibility" into "one Composer dependency and one cron line." That is often the difference between shipping queue monitoring this quarter and deferring it behind an infrastructure budget line.
- Hosting tier as a product decision rather than a platform ticket. Shared hosting, cPanel/Plesk, a single small VPS, or a cron-only PaaS become legitimate homes for a Redis-backed queue. For a PM, that widens the deployment options for a low-volume product without changing the product's operational story.
- Build vs. buy on supervisor glue. The honest comparison is not "package or nothing." It is: a hand-written Supervisor/systemd unit vs. this MIT package vs. a scheduled artisan liveness command we maintain ourselves. At this price point the buy side is trivially cheap; the real question is whose failure semantics we want to own. That is a product/ops risk call, not a cost call.
- Environment strategy and sequencing. Strong fit for staging, QA, demo, and single-tenant on-prem builds where the customer owns the box and won't install a process manager. It also lets a team adopt Horizon before investing in proper process supervision — decoupling two infrastructure changes that would otherwise ship in the same release, with rollback measured in "delete a cron line."
- An explicit written "not for us" boundary. Cron granularity is one minute at best, sometimes five or fifteen on throttled hosts. Any roadmap item carrying a job-latency SLA, or any high-throughput workload, routes to Supervisor/systemd/Kubernetes. Writing that boundary down is itself a useful product artifact — it prevents the package from quietly becoming a silent failure mode on the critical path.
- Dependency risk acceptance as a named decision. 63 stars, zero dependents, single maintainer. That is effectively an internal dependency on the critical job-processing path. Acceptable for replaceable glue; it belongs in the dependency inventory with a named owner, a pinned version, and a tested fallback.
When to Consider This Package
Adopt when all of these hold:
- Horizon is the right runtime and you're on Redis (Horizon does not cover SQS or database queues).
- The host gives you cron but no persistent process manager — or gives you one you don't want to operate.
- Queue volume is modest: a restart window of up to a minute is tolerable, and jobs aren't strictly time-critical. Jobs stay in Redis until a worker reserves them, so the exposure is latency, not data loss.
- You run a small number of servers. Multi-node Horizon fleets and autoscaling need real supervision and health checks.
- Someone has read the source and confirmed three things: how "Horizon is running" is actually determined (PID file vs. process table vs. Horizon's own status), how stale or recycled PIDs are handled, and whether a lock prevents overlapping cron invocations. Note the conflict in the source material: the package description implies a bounded-run model (boot, drain for a window, exit, re-invoke) while the prior assessment describes a liveness-poll model (check and restart if dead). These have different failure modes and different tuning knobs. Confirm which one the code implements before committing to a plan.
Look elsewhere when:
- Throughput or latency is on an SLA. Supervisor reacts to child exit in milliseconds; cron polls at best once a minute.
- Deploys must not stall the queue. Zero-downtime deploys typically call
horizon:terminate and depend on immediate supervisor restart. Under cron, restart waits for the next tick — up to a minute of queue stall on every deploy unless you explicitly re-trigger the check in the pipeline.
- You already have a real lifecycle manager — Kubernetes, ECS service definitions, Vapor, Forge daemons. There the package is strictly redundant complexity and actively degrades a working setup.
- Bus factor matters on a revenue-critical path. Single maintainer, low adoption, no commercial backing. Fine as glue with a tested fallback; not fine unguarded.
- Compliance or audit requires vendor-backed support. MIT glue with community issues only won't clear that bar.
Mitigations if we adopt: pin the version, read the source once, keep a tested fallback (a hand-written scheduled command or a Supervisor unit we can re-enable), and alert independently on Horizon process age and queue depth so a failed restart is detected without relying on the supervisor itself.
How to Pitch It (Stakeholders)
For executives. Our queue workers need a long-running process, which normally forces managed hosting or a dedicated process supervisor. This package keeps Horizon — the dashboard we want for queue visibility, retries, and job metrics — alive using scheduled cron, which our current hosting already provides. Net effect: production-grade queue observability without new infrastructure spend or a new ops runbook. The trade-off is bounded and honest: recovery from a crashed worker can take up to a minute instead of seconds, which is acceptable at our volume and affects latency, not job loss. Cost is one MIT dependency plus roughly a day of integration, source review, and a staging kill-test to prove the actual recovery window. One caveat to accept explicitly: this is a small, single-maintainer package, so we pin the version and keep a documented fallback.
For engineering. It's a cron-based supervisor for Horizon: a scheduled check that keeps Horizon running, reusing the existing config/horizon.php supervisors and queues. No Supervisor unit, no init system, no schema or queue-driver change, no application-code change — just one cron entry under the deploy user. Upside is portability across cheap hosts and a much smaller ops surface. Downside is that cron is a polling supervisor, so restart guarantees are weaker than Supervisor's event-driven model, and deploys calling horizon:terminate will stall the queue until the next tick unless we re-trigger the check in the pipeline. Before cutover: read the source and confirm which mechanism it actually implements (liveness-poll vs. bounded-run), that a lock prevents overlapping spawns, and that stale or recycled PIDs can't produce a false "healthy" reading. Then kill the master on staging, measure real recovery time, and check whether queue depth stays flat or sawtooths under expected peak load. Parallel-run against the Supervisor baseline for a week or two. Don't use it where job latency is on an SLA, and don't use it to dodge proper supervision on a multi-node deployment where we'll need it anyway.