Four job queues, each filling on its own slow drift plus the occasional surge. A fixed pool of workers drains queues, one per lane at rest — no spare capacity sitting idle. Drag a worker onto another lane to move it there, but it takes a beat to spin up before it starts draining again. That warm-up is the whole game: thrash workers around reactively and you pay the warm-up tax over and over while queues you just abandoned back up. Watch the telegraph — each queue flashes a warning a couple of seconds before a surge lands — and reposition ahead of it instead.
Timed to a recent deep-dive on Rails 8.1’s Solid Queue and the “run jobs inside the web process” tradeoff: this is that worker-allocation problem, stripped to its shape.
Reuse
The mechanic lives in src/backpressure.js as a framework-free ES module:
createBackpressureSim(opts)— returns a state object; callupdate(dt)each frame andassign(workerId, queueIndex)to move a worker.opts:queueCount,workerCount,capacity,drainRate,warmupTime,baseRate,rateAmplitude,surgeMultiplier,surgeDuration,warnLead,surgeIntervalMin/Max,duration(0 for an endless run).- State exposes
queues(each withfill,rate,dropped,warning,surge),workers(each withqueueIndex,warmup),totalDropped, andstatus('playing'|'finished'). No rendering or input in the module itself — the demo’s canvas drawing and pointer-drag handling are reference code, not part of the reusable piece.
Gotchas
- Each queue’s arrival rate is a sine wave (
baseRate ± rateAmplitude) so its rhythm is readable on its own; surges are a random multiplier layered on top, telegraphed viawarningstartingwarnLeadseconds before they land. Both signals are inqueue.rate/queue.warning— plot or read them, don’t recompute the wave yourself. - Defaults leave one worker per queue at rest (no slack), tuned so a
surge left uncovered usually overflows but a smart cover-then-return
policy roughly cuts drops to a fifth of doing nothing. Changing
workerCountrelative toqueueCountchanges that balance a lot. - The demo bundles its own copy of the module (self-contained by
contract). If you touch
src/, re-copy it intodemo/.