yangusik/laravel-balanced-queue
Balanced queue scheduling for Laravel that spreads jobs evenly across workers to prevent bottlenecks, improve throughput, and keep processing fair. Drop-in configuration works with existing queue connections and supports priorities.
What this package is. laravel-balanced-queue is a third-party Laravel queue driver that replaces the stock redis driver with one that distributes work across a pool of Redis connections/nodes. v1.3.3 is a patch release containing four bug fixes and no new features, deprecations, or documented breaking changes — so this establishes a baseline assessment rather than revising one.
Architecture fit. Narrow. Laravel's built-in redis driver already accepts an array of connections for random balancing, and Laravel Horizon covers most multi-node operational needs (supervision, metrics, retry/failure UI). This package is only a fit if we specifically need balancing semantics Laravel doesn't offer (e.g. weighted or load-aware distribution) and we are prepared to own a fork of framework internals. Absent that, it is a net-negative trade: we take on deep coupling to Illuminate\Queue\Jobs\RedisJob to solve a problem we may not have.
Evidence from the release notes — and what it implies.
maxTries is reachable. Pre-1.3.3, maxTries was effectively unreachable. This is a correctness defect with unbounded-retry consequences: a poison job could loop indefinitely, consuming workers and Redis memory. It also means failed_jobs was under-populated, so existing failure dashboards and alerting would have been silently wrong.release()/delete() set base Job flags directly instead of calling RedisJob:: methods that target stock keys. This is the most important signal for us. The package cannot reuse Laravel's RedisJob behavior because that behavior is hard-coded to stock key names. It must therefore track and re-implement internal job semantics on every Laravel minor release. That is a permanent maintenance tax and a structural fragility, not a one-off bug.retry_after semantics before we trust it.PendingDispatch::afterCommit. Indicates the driver does not transparently inherit all of Laravel's dispatch lifecycle behavior. Any team relying on afterCommit, dispatchAfterResponse, or chained/batched jobs must assume gaps exist elsewhere until proven otherwise.Technical risk: high. Single-maintainer project with community-contributed fixes; four correctness bugs — two of them data-integrity class — landed in a single patch release; and the design requires ongoing reverse-engineering of Laravel queue internals. Patch-level versioning here is not a reliable proxy for risk.
Key questions to resolve before adoption.
RedisJob or re-implement it? Which exact Laravel versions (5.x–11.x?) are in the supported test matrix, and is CI green against the versions we run?retry_after, and can it double-deliver to a live worker? Is recovery a background command, a scheduled task, or on-pop migration?redis driver (retries, maxTries, backoff, timeouts, failed_jobs, afterCommit, batches, chains)?Stack fit. Compatible at the Composer and configuration level — it is a queue driver, so integration is a config/queue.php swap plus a connection pool definition. No application code changes are required in principle. The risk is concentrated in behavioral parity, not installability.
Migration path. Do not migrate. Run it alongside the existing driver on a scoped queue:
"yangu sik/laravel-balanced-queue": "1.3.3" — pin, do not use ^), with a composer.json note that upgrades require a re-review of this assessment.redis driver configured and reachable so rollback is a config change, not a deploy.Compatibility work required. Verify against our exact Laravel and PHP versions in a branch, running our own queue test suite plus targeted cases for afterCommit, maxTries exhaustion, release() with delay, worker SIGKILL mid-job (reservation recovery), and duplicate-delivery on a slow worker. The SIGKILL and slow-worker tests are the gating ones — they exercise exactly what #21 and #19 fixed.
Sequencing. (1) Version-matrix and internals-coupling spike, ~1 week. (2) Conformance tests written against our workload, on a branch. (3) One non-critical queue in staging under synthetic load for two weeks. (4) One non-critical queue in production for 30 days with rollback armed. (5) Re-assess before any expansion. Treat step 5 as a genuine go/no-go, not a formality.
Maintenance. The dominant cost is not the package's own defects but its coupling to Laravel internals. Every Laravel minor upgrade becomes a review item: confirm RedisJob protected properties, key conventions, and job-flag semantics are unchanged. Budget roughly one engineering day per Laravel upgrade cycle for verification, indefinitely. With a single maintainer, we should also budget for the possibility of forking — which means our team must be able to read and modify the driver, not just consume it.
Support. No vendor, no SLA, community issues only. Four correctness fixes in one patch suggests issue volume is real and turnaround depends on volunteer PRs. We would be self-supporting for anything urgent.
Scaling. Balancing across nodes is the package's purpose, so horizontal scale is plausible, but two caveats: the reserved payload copy roughly increases per-job Redis footprint, which matters at high queue depth; and recovery sweeps add a periodic read/write load whose cost scales with the number of in-flight reservations. Model both at 2–3x current peak before committing.
Failure modes to monitor.
attempts or premature failed_jobs insertion. Pin versions and gate upgrades behind the conformance suite.Ramp-up. Moderate. Any engineer can use the driver; only someone who has read Laravel's RedisQueue/RedisJob internals can debug it. Identify at least two engineers who can operate at that depth, or accept that incidents on this queue escalate to a single person — which is itself a reason to keep the blast radius at one non-critical queue.
Recommendation. Not a production default. This release fixes real, serious defects — maxTries unreachability and unrecoverable reservations were genuine blockers — so v1.3.3 is the first version worth evaluating at all. But the fixes also confirm the package re-implements framework internals and will keep needing to. Approve a bounded pilot on one non-critical queue with an exact version pin, rollback armed, and a scheduled re-assessment; do not approve broad adoption, and do not treat the patch-level version number as evidence of stability.
How can I help you explore Laravel packages today?