Background jobs / Scaling simulator
Queue Autoscaling Playground
Will extra workers arrive soon enough to help, or will startup delay and a downstream cap turn scaling into wasted work?
Interactive calculations run in your browser; the initial example is pre-rendered. There are no accounts, uploads, or live queue connections. Inputs stay in page memory; the site does not persist them, put them in URLs, or send them to analytics. A worksheet download includes only what you explicitly export.
Capacity arrives after the scaling decision
| Policy | Completed / accepted | Unfinished | Completed jobs/s | Rejected | Not yet arrived | Missed / matured deadlines | P95 completed latency | Worker-seconds | Worker starts |
|---|---|---|---|---|---|---|---|---|---|
| Fixed warm pool | 29 / 84 | 55 | 0.12 | 0 | 0 | 68 / 79 | 192 s | 240 | 1 |
| Unfinished-depth target | 84 / 84 | 0 | 0.35 | 0 | 0 | 34 / 79 | 96 s | 1,340 | 12 |
| Oldest-age step controller | 84 / 84 | 0 | 0.35 | 0 | 0 | 57 / 79 | 120 s | 1,735 | 12 |
- Fixed warm pool
- Unfinished-depth target
- Oldest-age step controller
- Fixed warm pool
- Unfinished-depth target
- Oldest-age step controller
The depth controller sees unfinished work, while the step controller reacts to the oldest queued job. Starting more workers is not instantaneous capacity. Busy workers marked for retirement finish their jobs; their time still counts. A flat completion rate beside a growing pool can indicate the modeled downstream cap, not a need for still more workers.
Inspect the reproducible traces
Fixed warm pool: job and clock trace
| Time | Requested / target / live | Decision |
|---|---|---|
| 0 s | 1 / 1 / 1 | Keep current target |
| 5 s | 1 / 1 / 1 | Keep current target |
| 10 s | 1 / 1 / 1 | Keep current target |
| 15 s | 1 / 1 / 1 | Keep current target |
| 20 s | 1 / 1 / 1 | Keep current target |
| 25 s | 1 / 1 / 1 | Keep current target |
| 30 s | 1 / 1 / 1 | Keep current target |
| 35 s | 1 / 1 / 1 | Keep current target |
| 40 s | 1 / 1 / 1 | Keep current target |
| 45 s | 1 / 1 / 1 | Keep current target |
| 50 s | 1 / 1 / 1 | Keep current target |
| 55 s | 1 / 1 / 1 | Keep current target |
| 60 s | 1 / 1 / 1 | Keep current target |
| 65 s | 1 / 1 / 1 | Keep current target |
| 70 s | 1 / 1 / 1 | Keep current target |
| 75 s | 1 / 1 / 1 | Keep current target |
| 80 s | 1 / 1 / 1 | Keep current target |
| 85 s | 1 / 1 / 1 | Keep current target |
| 90 s | 1 / 1 / 1 | Keep current target |
| 95 s | 1 / 1 / 1 | Keep current target |
| Job | Arrives / service | Starts | Finishes | State at cutoff |
|---|---|---|---|---|
| baseline-1 | 0 s / 8 s | 0 s | 8 s | completed |
| baseline-2 | 10 s / 8 s | 10 s | 18 s | completed |
| baseline-3 | 20 s / 8 s | 20 s | 28 s | completed |
| baseline-4 | 30 s / 8 s | 30 s | 38 s | completed |
| baseline-5 | 40 s / 8 s | 40 s | 48 s | completed |
| baseline-6 | 50 s / 8 s | Not started | Not completed | waiting |
| baseline-7 | 60 s / 8 s | Not started | Not completed | waiting |
| baseline-8 | 70 s / 8 s | Not started | Not completed | waiting |
| baseline-9 | 80 s / 8 s | Not started | Not completed | waiting |
| baseline-10 | 90 s / 8 s | Not started | Not completed | waiting |
| baseline-11 | 100 s / 8 s | Not started | Not completed | waiting |
| baseline-12 | 110 s / 8 s | Not started | Not completed | waiting |
| baseline-13 | 120 s / 8 s | Not started | Not completed | waiting |
| baseline-14 | 130 s / 8 s | Not started | Not completed | waiting |
| baseline-15 | 140 s / 8 s | Not started | Not completed | waiting |
| baseline-16 | 150 s / 8 s | Not started | Not completed | waiting |
| baseline-17 | 160 s / 8 s | Not started | Not completed | waiting |
| baseline-18 | 170 s / 8 s | Not started | Not completed | waiting |
| baseline-19 | 180 s / 8 s | Not started | Not completed | waiting |
| baseline-20 | 190 s / 8 s | Not started | Not completed | waiting |
| Time | Queued / running | Ready / starting | Retiring / live | Oldest wait | Completed / rejected |
|---|---|---|---|---|---|
| 0 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 1 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 2 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 3 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 4 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 5 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 6 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 7 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 8 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 9 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 10 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 11 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 12 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 13 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 14 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 15 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 16 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 17 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 18 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 2 / 0 |
| 19 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 2 / 0 |
Unfinished-depth target: job and clock trace
| Time | Requested / target / live | Decision |
|---|---|---|
| 0 s | 1 / 1 / 1 | Keep current target |
| 5 s | 1 / 1 / 1 | Keep current target |
| 10 s | 1 / 1 / 1 | Keep current target |
| 15 s | 1 / 1 / 1 | Keep current target |
| 20 s | 1 / 1 / 1 | Keep current target |
| 25 s | 1 / 1 / 1 | Keep current target |
| 30 s | 1 / 1 / 1 | Keep current target |
| 35 s | 1 / 1 / 1 | Keep current target |
| 40 s | 12 / 12 / 12 | Cancel retirement or launch workers |
| 45 s | 12 / 12 / 12 | Keep current target |
| 50 s | 12 / 12 / 12 | Keep current target |
| 55 s | 12 / 12 / 12 | Keep current target |
| 60 s | 12 / 12 / 12 | Keep current target |
| 65 s | 12 / 12 / 12 | Keep current target |
| 70 s | 12 / 12 / 12 | Keep current target |
| 75 s | 12 / 12 / 12 | Keep current target |
| 80 s | 12 / 12 / 12 | Keep current target |
| 85 s | 12 / 12 / 12 | Keep current target |
| 90 s | 12 / 12 / 12 | Keep current target |
| 95 s | 10 / 10 / 10 | Stop idle/starting workers; drain busy workers |
| Job | Arrives / service | Starts | Finishes | State at cutoff |
|---|---|---|---|---|
| baseline-1 | 0 s / 8 s | 0 s | 8 s | completed |
| baseline-2 | 10 s / 8 s | 10 s | 18 s | completed |
| baseline-3 | 20 s / 8 s | 20 s | 28 s | completed |
| baseline-4 | 30 s / 8 s | 30 s | 38 s | completed |
| baseline-5 | 40 s / 8 s | 40 s | 48 s | completed |
| baseline-6 | 50 s / 8 s | 132 s | 140 s | completed |
| baseline-7 | 60 s / 8 s | 136 s | 144 s | completed |
| baseline-8 | 70 s / 8 s | 140 s | 148 s | completed |
| baseline-9 | 80 s / 8 s | 140 s | 148 s | completed |
| baseline-10 | 90 s / 8 s | 144 s | 152 s | completed |
| baseline-11 | 100 s / 8 s | 148 s | 156 s | completed |
| baseline-12 | 110 s / 8 s | 148 s | 156 s | completed |
| baseline-13 | 120 s / 8 s | 152 s | 160 s | completed |
| baseline-14 | 130 s / 8 s | 156 s | 164 s | completed |
| baseline-15 | 140 s / 8 s | 156 s | 164 s | completed |
| baseline-16 | 150 s / 8 s | 160 s | 168 s | completed |
| baseline-17 | 160 s / 8 s | 164 s | 172 s | completed |
| baseline-18 | 170 s / 8 s | 170 s | 178 s | completed |
| baseline-19 | 180 s / 8 s | 180 s | 188 s | completed |
| baseline-20 | 190 s / 8 s | 190 s | 198 s | completed |
| Time | Queued / running | Ready / starting | Retiring / live | Oldest wait | Completed / rejected |
|---|---|---|---|---|---|
| 0 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 1 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 2 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 3 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 4 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 5 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 6 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 7 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 8 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 9 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 10 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 11 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 12 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 13 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 14 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 15 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 16 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 17 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 18 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 2 / 0 |
| 19 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 2 / 0 |
Oldest-age step controller: job and clock trace
| Time | Requested / target / live | Decision |
|---|---|---|
| 0 s | 1 / 1 / 1 | Keep current target |
| 5 s | 1 / 1 / 1 | Keep current target |
| 10 s | 1 / 1 / 1 | Keep current target |
| 15 s | 1 / 1 / 1 | Keep current target |
| 20 s | 1 / 1 / 1 | Keep current target |
| 25 s | 1 / 1 / 1 | Keep current target |
| 30 s | 1 / 1 / 1 | Keep current target |
| 35 s | 1 / 1 / 1 | Keep current target |
| 40 s | 1 / 1 / 1 | Keep current target |
| 45 s | 1 / 1 / 1 | Keep current target |
| 50 s | 1 / 1 / 1 | Keep current target |
| 55 s | 1 / 1 / 1 | Keep current target |
| 60 s | 2 / 2 / 2 | Cancel retirement or launch workers |
| 65 s | 3 / 3 / 3 | Cancel retirement or launch workers |
| 70 s | 4 / 4 / 4 | Cancel retirement or launch workers |
| 75 s | 5 / 5 / 5 | Cancel retirement or launch workers |
| 80 s | 6 / 6 / 6 | Cancel retirement or launch workers |
| 85 s | 7 / 7 / 7 | Cancel retirement or launch workers |
| 90 s | 8 / 8 / 8 | Cancel retirement or launch workers |
| 95 s | 9 / 9 / 9 | Cancel retirement or launch workers |
| Job | Arrives / service | Starts | Finishes | State at cutoff |
|---|---|---|---|---|
| baseline-1 | 0 s / 8 s | 0 s | 8 s | completed |
| baseline-2 | 10 s / 8 s | 10 s | 18 s | completed |
| baseline-3 | 20 s / 8 s | 20 s | 28 s | completed |
| baseline-4 | 30 s / 8 s | 30 s | 38 s | completed |
| baseline-5 | 40 s / 8 s | 40 s | 48 s | completed |
| baseline-6 | 50 s / 8 s | 160 s | 168 s | completed |
| baseline-7 | 60 s / 8 s | 160 s | 168 s | completed |
| baseline-8 | 70 s / 8 s | 162 s | 170 s | completed |
| baseline-9 | 80 s / 8 s | 164 s | 172 s | completed |
| baseline-10 | 90 s / 8 s | 165 s | 173 s | completed |
| baseline-11 | 100 s / 8 s | 167 s | 175 s | completed |
| baseline-12 | 110 s / 8 s | 168 s | 176 s | completed |
| baseline-13 | 120 s / 8 s | 168 s | 176 s | completed |
| baseline-14 | 130 s / 8 s | 170 s | 178 s | completed |
| baseline-15 | 140 s / 8 s | 172 s | 180 s | completed |
| baseline-16 | 150 s / 8 s | 173 s | 181 s | completed |
| baseline-17 | 160 s / 8 s | 175 s | 183 s | completed |
| baseline-18 | 170 s / 8 s | 176 s | 184 s | completed |
| baseline-19 | 180 s / 8 s | 180 s | 188 s | completed |
| baseline-20 | 190 s / 8 s | 190 s | 198 s | completed |
| Time | Queued / running | Ready / starting | Retiring / live | Oldest wait | Completed / rejected |
|---|---|---|---|---|---|
| 0 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 1 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 2 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 3 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 4 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 5 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 6 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 7 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 0 / 0 |
| 8 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 9 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 10 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 11 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 12 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 13 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 14 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 15 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 16 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 17 s | 0 / 1 | 1 / 0 | 0 / 1 | 0 s | 1 / 0 |
| 18 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 2 / 0 |
| 19 s | 0 / 0 | 1 / 0 | 0 / 1 | 0 s | 2 / 0 |
A scaling target is not instant processing capacity
The same burst runs through a fixed pool, an unfinished-depth target, and an oldest-age step controller. Inspect startup, cooldown, and graceful retirement before comparing worker-seconds. A downstream limit can hold completions flat even as the pool grows. These deliberately small controllers explain feedback and delay; they are not provider configuration generators or cost forecasts.
Assumptions and limits
- A finite, deterministic trace runs on a one-second clock. Completions happen before arrivals, scaling, and dispatch. At the cutoff only completions are processed; new work is not started.
- Each worker runs one non-preemptible job at a time. A job occupies one downstream slot for its entire service duration. This is a concurrency bottleneck, not a universal requests-per-second model.
- Admission is tail-drop at a global unfinished-job limit, including running work. Rejection is explicit and never retried automatically; tenant scheduling does not make admission tenant-fair.
- Round robin rotates by JOB, not CPU time. Priority is strict but non-preemptive. The per-tenant cap restricts simultaneous running jobs; idle capacity can remain when every queued tenant is capped.
- Completion percentiles describe only jobs completed before cutoff. Pending and rejected counts, and oldest unstarted wait, must be read alongside them; no service before cutoff is not proof of permanent starvation.
- Deadlines use acceptance/arrival time and include waiting plus service. Only accepted jobs whose deadlines have matured by cutoff enter the deadline count; rejected work remains a separate outcome.
- Worker-seconds count booting, idle, busy, and gracefully draining workers in [0, cutoff). No price, real scheduler behavior, retry storm, network latency, or production SLO is inferred.
- Baseline arrivals are spaced evenly across the observation interval; an extra burst arrives at one explicit second. Every job has the same service time and uses FIFO.
- The minimum pool is already warm at second zero. Newly launched workers wait for startup; starting workers count toward controller targets and the maximum live pool.
- The depth controller targets ceil((waiting + running) / jobs-per-worker). The age controller adds one worker per poll at or above the age target and removes one below half the target; nonempty work wakes a zero-sized pool.
- Downscaling is held for the cooldown after any applied target change. It stops idle/starting workers first and retires busy workers after completion; a new scale-up can cancel retirement.
- These are explicitly defined teaching controllers, not replicas of Kubernetes HPA, KEDA, SQS scaling, or a provider's billing rules. No retries, job preemption, worker failures, or stochastic arrivals are included.
