Build1 distinct publisher3 min readUpdated
A dev.to writeup swaps a hardcoded Laravel worker count for one declared SLA and pending-over-throughput math. The measured run shows where the formula stops and the caps take over.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
A developer spent a week on a demo app replacing the hardcoded worker count in a Laravel supervisor config with a declared pickup deadline, using cboxdk/laravel-queue-autoscale plus cboxdk/laravel-queue-metrics, and published the measurements [1]. The reason to read it is not the package: it is that `numprocs=10` is a number nobody at your company can defend, picked years ago and left there while the load changed around it [2].
The failure is symmetric. Set it too low and jobs wait minutes during a campaign blast; set it too high and you pay for RAM all night for workers doing nothing [3]. The alternative is to declare one thing, a service level such as "a job on this queue must be picked up within 10 seconds", and let a manager process solve every five seconds for workers = (pending jobs / SLA seconds) / jobs per second per worker [5]. With 3,000 pending jobs and a 10-second promise you need 300 jobs per second; a job that takes about 100ms gives one worker about 10 per second, so the formula asks for 30 workers [6]. This is Little's Law, the 1961 result behind checkout lines and CPU schedulers, and the point is that the only human input is a business question rather than a process count [7]. If you have ever sized a PHP-FPM pool as RAM divided by average process size, it is the same move: measure one unit, derive the count [8].
What the run actually did is the interesting part. The configuration capped the queue at 16 workers, and the cap won over the formula's 30; the package also caps by measured host CPU and RAM [10]. Sixteen workers at ten jobs a second is 160 jobs a second, so a 3,000-job backlog needs roughly 18.75 seconds to clear, which means at the cap the declared 10-second promise is arithmetically unreachable and the cap, not the SLA, is the operating policy [12]. That is a useful thing to be able to say out loud. All 3,000 jobs completed with none lost, and on SIGTERM each worker finished its in-flight job before exiting [11].
The guardrail worth stealing is the failure fuse. With 2,000 jobs that all throw, the manager logged a 100% failure rate over 28 jobs and held at the minimum, noting that the backlog of 1,999 required 999.5 workers to prevent an SLA breach [13]. It allowed one, roughly a thousandfold gap between what the backlog demanded and what was permitted [15], keeping that worker as a probe until the failure window aged out at 0% over 387 jobs and normal scaling resumed without a restart [14].
Cost behaviour is deliberately asymmetric: scale-down removes one worker per cycle with an anti-flapping cooldown [16], so returning from 16 workers to 1 takes at least fifteen five-second cycles, about 75 seconds, before any cooldown [17]. You pay a short idle tail on purpose instead of yo-yoing.
Two operational notes from the same writeup: the manager needs ext-pcntl, and v4 also ext-posix, and every queue entry needs an explicit `connection` or it silently hunts for a connection named `default` and every evaluation fails into the log [18]. Delivery semantics do not change. Laravel's Redis reservation pops and reserves in one single-threaded Lua script, so two workers cannot claim the same job [19], but the guarantee is still at-least-once: retry_after defaults to 90 seconds, a dead worker's job returns to pending, and idempotency, ShouldBeUnique and WithoutOverlapping remain your problem [20].
Watch your own per-worker rate before trusting any of this arithmetic; ten jobs a second is a 100ms demo job, not a PDF renderer [6]. Then check whether the SLA you declare implies a worker count you are willing to fund, and whether a 28-job failure window matches how your payment provider actually dies [13].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
The author tested cboxdk/laravel-queue-autoscale together with cboxdk/laravel-queue-metrics on a demo app over a week and reported his own measured results.
Every Laravel deployment the author has seen contains a supervisor line like numprocs=10; nobody knows why the number is 10, someone picked it years ago and it stayed, and it is wrong in both directions because load changes and the config does not.
Too few workers means jobs wait minutes during a campaign blast; too many means burning RAM all night on workers doing nothing.
The autoscale package was built by Sylvester Damgaard, who worked on the queue manager at Laravel.
You declare one SLA, for example that a job on a queue must be picked up within 10 seconds, and every 5 seconds a manager process solves workers = (pending jobs / SLA seconds) / jobs per second per worker.
3,000 pending jobs with a 10-second target requires 300 jobs per second; the author's demo job takes about 100ms, so one worker does about 10 jobs per second, giving 30 workers.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Specific but self-reported and unreplicated
The mechanism is well specified and the runs are concrete: an exact formula, an evaluation interval, a config snippet, quoted manager log lines with job counts and failure percentages, and reported zero job loss with graceful SIGTERM drain. But all of it comes from one author's demo app in a single post, with no independent replication, no raw metrics series, and no production-scale run. The article's own numbers also leave the headline promise partly unverified: at the 16-worker cap the tested backlog cannot clear inside the declared 10-second target.
One demo-app trial, no deployments disclosed
Disclosed usage is a single week-long trial on a demo application by an author who is not the maintainer. The packages are described as a young project with one maintainer, the author found a bug during testing, and no production deployments, download figures, or third-party users appear anywhere in the supplied material.
Mildly overstated, but self-qualified
The framing — 'here is the math that replaces it', 'the difference between an autoscaler and a bash script' — runs slightly ahead of what one demo run on one host shows, and the measured burst ends with the caps, not the formula, deciding the worker count while the derived clear time exceeds the declared SLA. The gap stays modest because the author volunteers the important caveats: single-host scope, one maintainer, a bug he hit, a manager that itself needs supervising and re-learns lazily after restart, and unchanged at-least-once semantics.
Independent author, engagement-driven venue
The write-up is by a developer who is not the named maintainer and who criticises the tooling he tested, which limits promotional pressure. Residual incentive is venue-shaped: a developer-blog post rewards a strong contrarian hook ('your worker count is a guess') and a tidy narrative arc, and no disclosure exists either way about any relationship to the package authors.
Single-source, single-operator evidence
Confidence is capped by structure rather than content quality: one publisher, one author, one demo environment, and synthetic workloads. The mechanics described (Redis Lua reservation, at-least-once semantics, min/max caps) are checkable and internally consistent, which supports moderate confidence in the description of how the package behaves, but not in generalised performance or reliability claims.
build
Once the question needs a cube, you own the parser1 distinct publisher
build
PHP-FPM's dynamic pool is a one-second idle-worker loop, not a capacity plan1 distinct publisher
build
The database was fine: a one-in-three DNS failure hidden by an app that logs nothing1 distinct publisher
build
The network already knew: UPS and WAN state as keys a cluster can reconcile against1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 21, 2026