vdlp/oc-horizon-plugin
Integrates Laravel Horizon into October CMS so you can monitor and manage Redis-backed queues from Horizon's dashboard, with job metrics, retries, and workload insights available inside your October CMS project.
What the package is. vdlp/oc-horizon-plugin is an adapter that installs Laravel Horizon — Laravel's first-party Redis queue dashboard and supervisor orchestrator — into October CMS's backend. The value proposition is narrow but real: queue throughput, wait times, failed-job retry/delete, and supervisor configuration exposed inside the CMS the team already logs into, instead of a bespoke dashboard, redis-cli, or raw failed_jobs queries. The underlying capability (Horizon) is well-understood and stable; only the glue is third-party.
Architecture fit. Reasonable at the framework layer — October runs on Laravel, so Horizon's service provider, routes, and assets can be registered through October's plugin lifecycle. The fit is imperfect at three seams a TPM should note as acceptance criteria, not implementation trivia: (1) service-provider and route registration inside October's Plugin::register()/boot() rather than a stock AppServiceProvider; (2) authorization, where Horizon expects a Laravel Gate/Horizon::auth callback but October supplies its own backend user, role, and permission model; (3) asset publishing and URL prefixing, which diverge from stock Laravel's public/vendor/horizon. Each seam is a place where an upgrade to either parent project can break behavior silently.
Integration feasibility. High for an October CMS estate already running queues on Redis. Low-to-zero value otherwise — Horizon only manages Redis connections, so a database or sync queue yields an empty dashboard and a false sense of coverage. The real cost is not the plugin but its prerequisites: a reachable Redis instance in every environment where Horizon runs, a process supervisor for the horizon daemon, and a deploy pipeline that terminates Horizon on release. None of that is delivered by the package.
Technical risk — the dominant issue is maintenance status. The repository is archived. That reframes the evaluation entirely: there is no upstream fix path for a Horizon major bump, an October major bump, a PHP version floor, or a security issue in the adapter. Adoption means the team inherits ownership of the adapter, whether or not anyone has said so out loud. Compounding this:
Decision framing. Given archived status, the realistic options are: (a) adopt and pin to a known-good tag, accepting that the team owns all future compatibility work; (b) internalize — fork, vendor, or hand-wire Horizon into October directly (Horizon is a documented Laravel package; the adapter is arguably tens of lines of service-provider and navigation registration, which may be cheaper to own than a fork); (c) defer and use Horizon standalone outside the CMS backend meanwhile. A TPM should size option (b) before defaulting to (a) — the build cost may be lower than the fork-maintenance cost, and it removes the GPL and archived-dependency questions simultaneously.
Key questions to close before commitment:
october/*, laravel/framework, laravel/horizon, or PHP floor?Stack fit gates. Three prerequisites, each a go/no-go: Redis is the queue backend in the environment(s) where Horizon will run; the plugin's declared October/PHP/Laravel constraints match our install; and a process supervisor (systemd, supervisord, or container sidecar) exists or will be built for the horizon daemon. If any is missing, the effort estimate is not "install a plugin" — it is an infrastructure workstream, and should be scoped and sequenced as one.
Migration path. Additive and reversible in principle: Composer require, October migrate, publish Horizon config and assets, bind authorization. No application schema changes beyond Horizon's own tables and Redis keys; no queue payload changes. Rollback is a version pin plus a config-cache clear, with orphaned Horizon Redis keys as the residual — deliberate flush if the connection is shared. This low blast radius is a genuine advantage and makes a staged pilot cheap.
Compatibility verification. Treat 3.4.0 as unverified, not as "probably fine." Pin explicitly to a reviewed tag until the diff is read and a staging run confirms behavior under our PHP/October/Laravel matrix. Check specifically that a Horizon version required transitively by the plugin does not conflict with one already resolved elsewhere in the app — adapter packages that pin transitively are a common source of resolution deadlock.
Sequencing.
composer.json deltas; classify patch-equivalent vs. behavioral. This is the cheapest risk-retirement step available.horizon under systemd/supervisord, and php artisan horizon:terminate inserted into the release sequence (distinct from queue:restart — it drains and respawns supervisors).Ecosystem fit beyond the pilot. Decide up front whether Horizon's dashboard is the system of record for queue health or a convenience view. If alerting runs off Horizon's waits thresholds and Slack/mail routing, that is a dependency on a package we cannot upgrade independently — worth writing down as an owned risk with a named owner.
Maintenance ownership is the headline. With the repository archived, "maintenance" is not a vendor activity — it is a line item on our roadmap. Concretely, that means someone must own: watching Laravel/October/Horizon major releases and validating the adapter against them, re-publishing Horizon assets when the bundle drifts (a stale bundle surfaces as a 404 in the dashboard, not an obvious failure), and reviewing each October upgrade for service-provider or permission-model changes. If no team will accept that ownership, the correct outcome is to internalize or defer, not to install and hope.
Support model. No vendor, no SLA, no security response channel. Internal support will be first-line engineers reading source. Budget onboarding time for that reality; it is small code but unfamiliar-to-most glue.
Deployment and change management. The recurring operational cost is process hygiene, and it is easy to get wrong in ways that look like application bugs:
config/horizon.php edits do nothing until config cache is cleared and Horizon is terminated — the most common cause of "the new supervisor didn't start."memory, maxJobs, maxTime, tries, timeout must be set explicitly per supervisor; October workers boot the full CMS and accumulate memory and stale DB connections if left on defaults.job timeout < supervisor timeout < retry_after) must be validated in review; violating it produces duplicate job executions, which are expensive to diagnose and erode trust in the queue.Failure modes to document and monitor.
redis-cli ping before opening a ticket on the plugin.APP_ENV key mismatch in environments causes a fallback to a single worker with no balancing — jobs still process, so nobody notices until latency degrades.failed_jobs/job_batches migrations; skipping the October migrate step produces exceptions on the first failure after an upgrade — precisely when you need the dashboard to work.Scaling. Horizon's own balancing strategies (simple/auto) are mature and the plugin does not interfere with them meaningfully. Scaling considerations that sit outside the plugin: Redis availability and memory (Horizon stores metrics and supervisor state there — a Redis restart mid-flight is a queue-availability event), and the cardinality of queues. Routing jobs to dedicated queues rather than a single default queue is the highest-leverage configuration change, because per-queue wait-time metrics are what make the dashboard diagnostically useful rather than decorative.
Ramp-up. Engineers: low — one supervised process, one config file, one deploy hook; a half-day for someone already fluent in Laravel queues, longer for anyone who is not, since most of the learning is Horizon's semantics rather than the plugin's. Operations/on-call: moderate — the runbook must cover Redis health, empty-dashboard triage, horizon:terminate on deploy, and the failed-job retry path. Stakeholders: trivial, but worth a short demo — the visibility win is the justification for taking on the maintenance burden, and it should be shown to the people who funded the request.
Net TPM read. The functional gap this closes is real and the integration cost is genuinely low. The lifecycle cost is not: an archived, GPL-2.0, single-maintainer adapter with an undisclosed last release means we are buying a capability and inheriting a dependency. Proceed only with a named internal owner, a pinned version, a legal sign-off, and a documented internalize-or-fork fallback — or spend the equivalent effort wiring Horizon directly and skip the adapter entirely.
How can I help you explore Laravel packages today?