Skip to main content
José David Baena
Tools and working references

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.

Set a burst and controller constraints

Set a burst and controller constraints

Evenly spaced synthetic arrivals, not a sampled production rate.

All burst jobs arrive at the same second.

Must precede the cutoff when the burst is nonempty.

Every job occupies one worker and one downstream slot.

Completions at the cutoff count; new work is not started there.

From arrival to completion, including queue wait.

Already ready at second zero; also the fixed-pool baseline.

Includes starting and gracefully draining workers.

Zero stops processing. Extra workers cannot overcome this limit.

Starting workers consume worker-seconds without doing work.

The controller only observes and resizes on these boundaries.

Time since the last applied target change; zero permits churn.

Depth target = ceil((waiting + running) / this value).

Add one per poll above target; remove one below half target.

Overflow is rejected explicitly; retries are not modeled.

Capacity arrives after the scaling decision

Compare completed work, missed deadlines, and the cost of starting or draining workers
Same offered workload. Completion percentiles exclude unfinished/rejected jobs; worker starts include the initial warm pool.
PolicyCompleted / acceptedUnfinishedCompleted jobs/sRejectedNot yet arrivedMissed / matured deadlinesP95 completed latencyWorker-secondsWorker starts
Fixed warm pool29 / 84550.120068 / 79192 s2401
Unfinished-depth target84 / 8400.350034 / 7996 s1,34012
Oldest-age step controller84 / 8400.350057 / 79120 s1,73512
Waiting jobs after dispatch (jobs)
Waiting jobs after dispatchOne-second samples from 0 to 240 seconds, vertical scale 0 to 60 jobs. Solid and patterned lines match the legend. Exact values are in the per-policy trace tables and worksheet.
  • Fixed warm pool
  • Unfinished-depth target
  • Oldest-age step controller
Live pool, including startup and drain (workers)
Live pool, including startup and drainOne-second samples from 0 to 240 seconds, vertical scale 0 to 12 workers. Solid and patterned lines match the legend. Exact values are in the per-policy trace tables and worksheet.
  • 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
Fixed warm pool: controller observations and decisions
TimeRequested / target / liveDecision
0 s1 / 1 / 1Keep current target
5 s1 / 1 / 1Keep current target
10 s1 / 1 / 1Keep current target
15 s1 / 1 / 1Keep current target
20 s1 / 1 / 1Keep current target
25 s1 / 1 / 1Keep current target
30 s1 / 1 / 1Keep current target
35 s1 / 1 / 1Keep current target
40 s1 / 1 / 1Keep current target
45 s1 / 1 / 1Keep current target
50 s1 / 1 / 1Keep current target
55 s1 / 1 / 1Keep current target
60 s1 / 1 / 1Keep current target
65 s1 / 1 / 1Keep current target
70 s1 / 1 / 1Keep current target
75 s1 / 1 / 1Keep current target
80 s1 / 1 / 1Keep current target
85 s1 / 1 / 1Keep current target
90 s1 / 1 / 1Keep current target
95 s1 / 1 / 1Keep current target
Page 1 of 3
Fixed warm pool: individual jobs
JobArrives / serviceStartsFinishesState at cutoff
baseline-10 s / 8 s0 s8 scompleted
baseline-210 s / 8 s10 s18 scompleted
baseline-320 s / 8 s20 s28 scompleted
baseline-430 s / 8 s30 s38 scompleted
baseline-540 s / 8 s40 s48 scompleted
baseline-650 s / 8 sNot startedNot completedwaiting
baseline-760 s / 8 sNot startedNot completedwaiting
baseline-870 s / 8 sNot startedNot completedwaiting
baseline-980 s / 8 sNot startedNot completedwaiting
baseline-1090 s / 8 sNot startedNot completedwaiting
baseline-11100 s / 8 sNot startedNot completedwaiting
baseline-12110 s / 8 sNot startedNot completedwaiting
baseline-13120 s / 8 sNot startedNot completedwaiting
baseline-14130 s / 8 sNot startedNot completedwaiting
baseline-15140 s / 8 sNot startedNot completedwaiting
baseline-16150 s / 8 sNot startedNot completedwaiting
baseline-17160 s / 8 sNot startedNot completedwaiting
baseline-18170 s / 8 sNot startedNot completedwaiting
baseline-19180 s / 8 sNot startedNot completedwaiting
baseline-20190 s / 8 sNot startedNot completedwaiting
Page 1 of 5
Fixed warm pool: one-second samples after dispatch
TimeQueued / runningReady / startingRetiring / liveOldest waitCompleted / rejected
0 s0 / 11 / 00 / 10 s0 / 0
1 s0 / 11 / 00 / 10 s0 / 0
2 s0 / 11 / 00 / 10 s0 / 0
3 s0 / 11 / 00 / 10 s0 / 0
4 s0 / 11 / 00 / 10 s0 / 0
5 s0 / 11 / 00 / 10 s0 / 0
6 s0 / 11 / 00 / 10 s0 / 0
7 s0 / 11 / 00 / 10 s0 / 0
8 s0 / 01 / 00 / 10 s1 / 0
9 s0 / 01 / 00 / 10 s1 / 0
10 s0 / 11 / 00 / 10 s1 / 0
11 s0 / 11 / 00 / 10 s1 / 0
12 s0 / 11 / 00 / 10 s1 / 0
13 s0 / 11 / 00 / 10 s1 / 0
14 s0 / 11 / 00 / 10 s1 / 0
15 s0 / 11 / 00 / 10 s1 / 0
16 s0 / 11 / 00 / 10 s1 / 0
17 s0 / 11 / 00 / 10 s1 / 0
18 s0 / 01 / 00 / 10 s2 / 0
19 s0 / 01 / 00 / 10 s2 / 0
Page 1 of 13
Unfinished-depth target: job and clock trace
Unfinished-depth target: controller observations and decisions
TimeRequested / target / liveDecision
0 s1 / 1 / 1Keep current target
5 s1 / 1 / 1Keep current target
10 s1 / 1 / 1Keep current target
15 s1 / 1 / 1Keep current target
20 s1 / 1 / 1Keep current target
25 s1 / 1 / 1Keep current target
30 s1 / 1 / 1Keep current target
35 s1 / 1 / 1Keep current target
40 s12 / 12 / 12Cancel retirement or launch workers
45 s12 / 12 / 12Keep current target
50 s12 / 12 / 12Keep current target
55 s12 / 12 / 12Keep current target
60 s12 / 12 / 12Keep current target
65 s12 / 12 / 12Keep current target
70 s12 / 12 / 12Keep current target
75 s12 / 12 / 12Keep current target
80 s12 / 12 / 12Keep current target
85 s12 / 12 / 12Keep current target
90 s12 / 12 / 12Keep current target
95 s10 / 10 / 10Stop idle/starting workers; drain busy workers
Page 1 of 3
Unfinished-depth target: individual jobs
JobArrives / serviceStartsFinishesState at cutoff
baseline-10 s / 8 s0 s8 scompleted
baseline-210 s / 8 s10 s18 scompleted
baseline-320 s / 8 s20 s28 scompleted
baseline-430 s / 8 s30 s38 scompleted
baseline-540 s / 8 s40 s48 scompleted
baseline-650 s / 8 s132 s140 scompleted
baseline-760 s / 8 s136 s144 scompleted
baseline-870 s / 8 s140 s148 scompleted
baseline-980 s / 8 s140 s148 scompleted
baseline-1090 s / 8 s144 s152 scompleted
baseline-11100 s / 8 s148 s156 scompleted
baseline-12110 s / 8 s148 s156 scompleted
baseline-13120 s / 8 s152 s160 scompleted
baseline-14130 s / 8 s156 s164 scompleted
baseline-15140 s / 8 s156 s164 scompleted
baseline-16150 s / 8 s160 s168 scompleted
baseline-17160 s / 8 s164 s172 scompleted
baseline-18170 s / 8 s170 s178 scompleted
baseline-19180 s / 8 s180 s188 scompleted
baseline-20190 s / 8 s190 s198 scompleted
Page 1 of 5
Unfinished-depth target: one-second samples after dispatch
TimeQueued / runningReady / startingRetiring / liveOldest waitCompleted / rejected
0 s0 / 11 / 00 / 10 s0 / 0
1 s0 / 11 / 00 / 10 s0 / 0
2 s0 / 11 / 00 / 10 s0 / 0
3 s0 / 11 / 00 / 10 s0 / 0
4 s0 / 11 / 00 / 10 s0 / 0
5 s0 / 11 / 00 / 10 s0 / 0
6 s0 / 11 / 00 / 10 s0 / 0
7 s0 / 11 / 00 / 10 s0 / 0
8 s0 / 01 / 00 / 10 s1 / 0
9 s0 / 01 / 00 / 10 s1 / 0
10 s0 / 11 / 00 / 10 s1 / 0
11 s0 / 11 / 00 / 10 s1 / 0
12 s0 / 11 / 00 / 10 s1 / 0
13 s0 / 11 / 00 / 10 s1 / 0
14 s0 / 11 / 00 / 10 s1 / 0
15 s0 / 11 / 00 / 10 s1 / 0
16 s0 / 11 / 00 / 10 s1 / 0
17 s0 / 11 / 00 / 10 s1 / 0
18 s0 / 01 / 00 / 10 s2 / 0
19 s0 / 01 / 00 / 10 s2 / 0
Page 1 of 13
Oldest-age step controller: job and clock trace
Oldest-age step controller: controller observations and decisions
TimeRequested / target / liveDecision
0 s1 / 1 / 1Keep current target
5 s1 / 1 / 1Keep current target
10 s1 / 1 / 1Keep current target
15 s1 / 1 / 1Keep current target
20 s1 / 1 / 1Keep current target
25 s1 / 1 / 1Keep current target
30 s1 / 1 / 1Keep current target
35 s1 / 1 / 1Keep current target
40 s1 / 1 / 1Keep current target
45 s1 / 1 / 1Keep current target
50 s1 / 1 / 1Keep current target
55 s1 / 1 / 1Keep current target
60 s2 / 2 / 2Cancel retirement or launch workers
65 s3 / 3 / 3Cancel retirement or launch workers
70 s4 / 4 / 4Cancel retirement or launch workers
75 s5 / 5 / 5Cancel retirement or launch workers
80 s6 / 6 / 6Cancel retirement or launch workers
85 s7 / 7 / 7Cancel retirement or launch workers
90 s8 / 8 / 8Cancel retirement or launch workers
95 s9 / 9 / 9Cancel retirement or launch workers
Page 1 of 3
Oldest-age step controller: individual jobs
JobArrives / serviceStartsFinishesState at cutoff
baseline-10 s / 8 s0 s8 scompleted
baseline-210 s / 8 s10 s18 scompleted
baseline-320 s / 8 s20 s28 scompleted
baseline-430 s / 8 s30 s38 scompleted
baseline-540 s / 8 s40 s48 scompleted
baseline-650 s / 8 s160 s168 scompleted
baseline-760 s / 8 s160 s168 scompleted
baseline-870 s / 8 s162 s170 scompleted
baseline-980 s / 8 s164 s172 scompleted
baseline-1090 s / 8 s165 s173 scompleted
baseline-11100 s / 8 s167 s175 scompleted
baseline-12110 s / 8 s168 s176 scompleted
baseline-13120 s / 8 s168 s176 scompleted
baseline-14130 s / 8 s170 s178 scompleted
baseline-15140 s / 8 s172 s180 scompleted
baseline-16150 s / 8 s173 s181 scompleted
baseline-17160 s / 8 s175 s183 scompleted
baseline-18170 s / 8 s176 s184 scompleted
baseline-19180 s / 8 s180 s188 scompleted
baseline-20190 s / 8 s190 s198 scompleted
Page 1 of 5
Oldest-age step controller: one-second samples after dispatch
TimeQueued / runningReady / startingRetiring / liveOldest waitCompleted / rejected
0 s0 / 11 / 00 / 10 s0 / 0
1 s0 / 11 / 00 / 10 s0 / 0
2 s0 / 11 / 00 / 10 s0 / 0
3 s0 / 11 / 00 / 10 s0 / 0
4 s0 / 11 / 00 / 10 s0 / 0
5 s0 / 11 / 00 / 10 s0 / 0
6 s0 / 11 / 00 / 10 s0 / 0
7 s0 / 11 / 00 / 10 s0 / 0
8 s0 / 01 / 00 / 10 s1 / 0
9 s0 / 01 / 00 / 10 s1 / 0
10 s0 / 11 / 00 / 10 s1 / 0
11 s0 / 11 / 00 / 10 s1 / 0
12 s0 / 11 / 00 / 10 s1 / 0
13 s0 / 11 / 00 / 10 s1 / 0
14 s0 / 11 / 00 / 10 s1 / 0
15 s0 / 11 / 00 / 10 s1 / 0
16 s0 / 11 / 00 / 10 s1 / 0
17 s0 / 11 / 00 / 10 s1 / 0
18 s0 / 01 / 00 / 10 s2 / 0
19 s0 / 01 / 00 / 10 s2 / 0
Page 1 of 13

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.