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

Background jobs / Scheduling simulator

Tenant Fairness & Backpressure

Can a small interactive tenant get timely service while another tenant fills the queue with long-running 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.

Build a three-tenant workload

Build a three-tenant workload

Every third job is long; the rest use the short service time.

Short jobs, highest priority in the priority policy.

Long jobs, between interactive and bulk in priority.

Zero creates one burst at second zero.

Interactive arrivals start at 1 s; reports at 2 s.

One non-preemptible worker slot for this duration.

At least as long as the short service time.

One slot each; the pool is fixed for all policies.

Only the fourth policy applies this cap; it can leave workers idle.

Running plus waiting. Overflow is explicitly rejected, not retried.

Later arrivals are shown as future, not dropped.

Measured from each admitted arrival, including queue wait.

Same workload, different access to workers

36 offered jobs; compare each tenant, not only aggregate throughput
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
FIFO36 / 3600.150024 / 3692 s7203
Tenant round robin36 / 3600.150024 / 36108 s7203
Strict priority36 / 3600.150025 / 36110 s7203
Round robin + tenant cap36 / 3600.150026 / 36190 s7203
Waiting jobs after dispatch (jobs)
Waiting jobs after dispatchOne-second samples from 0 to 240 seconds, vertical scale 0 to 28 jobs. Solid and patterned lines match the legend. Exact values are in the per-policy trace tables and worksheet.
  • FIFO
  • Tenant round robin
  • Strict priority
  • Round robin + tenant cap
Per-tenant completion and waiting evidence across all four policies
Policy / tenantCompleted / acceptedPending / rejectedP95 completed latencyP95 wait of started jobsOldest unstarted wait
FIFO / bulk24 / 240 / 066 s52 sNone waiting
FIFO / interactive6 / 60 / 073 s71 sNone waiting
FIFO / reports6 / 60 / 092 s72 sNone waiting
Tenant round robin / bulk24 / 240 / 0108 s98 sNone waiting
Tenant round robin / interactive6 / 60 / 033 s31 sNone waiting
Tenant round robin / reports6 / 60 / 052 s32 sNone waiting
Strict priority / bulk24 / 240 / 0110 s96 sNone waiting
Strict priority / interactive6 / 60 / 017 s15 sNone waiting
Strict priority / reports6 / 60 / 046 s26 sNone waiting
Round robin + tenant cap / bulk24 / 240 / 0190 s188 sNone waiting
Round robin + tenant cap / interactive6 / 60 / 02 s0 sNone waiting
Round robin + tenant cap / reports6 / 60 / 0100 s80 sNone waiting

Round robin gives turns, not equal processing time. Long jobs can still occupy every worker. A concurrency cap creates room for another tenant but may reduce utilization. Try admission overload: a fair scheduler cannot rescue a quiet tenant whose work was rejected before entering the queue.

Inspect the reproducible traces

FIFO: job and clock trace
FIFO: per-tenant outcomes
TenantCompleted / acceptedPending / rejectedP95 completed latencyP95 wait of started jobsOldest unstarted wait
bulk24 / 240 / 066 s52 sNone waiting
interactive6 / 60 / 073 s71 sNone waiting
reports6 / 60 / 092 s72 sNone waiting
FIFO: individual jobs
JobArrives / serviceStartsFinishesState at cutoff
bulk-10 s / 20 s0 s20 scompleted
bulk-20 s / 2 s0 s2 scompleted
bulk-30 s / 2 s0 s2 scompleted
bulk-40 s / 20 s2 s22 scompleted
bulk-50 s / 2 s2 s4 scompleted
bulk-60 s / 2 s4 s6 scompleted
bulk-70 s / 20 s6 s26 scompleted
bulk-80 s / 2 s20 s22 scompleted
bulk-90 s / 2 s22 s24 scompleted
bulk-100 s / 20 s22 s42 scompleted
bulk-110 s / 2 s24 s26 scompleted
bulk-120 s / 2 s26 s28 scompleted
bulk-130 s / 20 s26 s46 scompleted
bulk-140 s / 2 s28 s30 scompleted
bulk-150 s / 2 s30 s32 scompleted
bulk-160 s / 20 s32 s52 scompleted
bulk-170 s / 2 s42 s44 scompleted
bulk-180 s / 2 s44 s46 scompleted
bulk-190 s / 20 s46 s66 scompleted
bulk-200 s / 2 s46 s48 scompleted
Page 1 of 2
FIFO: one-second samples after dispatch
TimeQueued / runningReady / startingRetiring / liveOldest waitCompleted / rejected
0 s21 / 33 / 00 / 30 s0 / 0
1 s22 / 33 / 00 / 31 s0 / 0
2 s21 / 33 / 00 / 32 s2 / 0
3 s21 / 33 / 00 / 33 s2 / 0
4 s20 / 33 / 00 / 34 s3 / 0
5 s21 / 33 / 00 / 35 s3 / 0
6 s21 / 33 / 00 / 36 s4 / 0
7 s21 / 33 / 00 / 37 s4 / 0
8 s21 / 33 / 00 / 38 s4 / 0
9 s22 / 33 / 00 / 39 s4 / 0
10 s23 / 33 / 00 / 310 s4 / 0
11 s23 / 33 / 00 / 311 s4 / 0
12 s23 / 33 / 00 / 312 s4 / 0
13 s24 / 33 / 00 / 313 s4 / 0
14 s25 / 33 / 00 / 314 s4 / 0
15 s25 / 33 / 00 / 315 s4 / 0
16 s25 / 33 / 00 / 316 s4 / 0
17 s26 / 33 / 00 / 317 s4 / 0
18 s27 / 33 / 00 / 318 s4 / 0
19 s27 / 33 / 00 / 319 s4 / 0
Page 1 of 13
Tenant round robin: job and clock trace
Tenant round robin: per-tenant outcomes
TenantCompleted / acceptedPending / rejectedP95 completed latencyP95 wait of started jobsOldest unstarted wait
bulk24 / 240 / 0108 s98 sNone waiting
interactive6 / 60 / 033 s31 sNone waiting
reports6 / 60 / 052 s32 sNone waiting
Tenant round robin: individual jobs
JobArrives / serviceStartsFinishesState at cutoff
bulk-10 s / 20 s0 s20 scompleted
bulk-20 s / 2 s0 s2 scompleted
bulk-30 s / 2 s0 s2 scompleted
bulk-40 s / 20 s4 s24 scompleted
bulk-50 s / 2 s22 s24 scompleted
bulk-60 s / 2 s26 s28 scompleted
bulk-70 s / 20 s42 s62 scompleted
bulk-80 s / 2 s50 s52 scompleted
bulk-90 s / 2 s62 s64 scompleted
bulk-100 s / 20 s64 s84 scompleted
bulk-110 s / 2 s66 s68 scompleted
bulk-120 s / 2 s68 s70 scompleted
bulk-130 s / 20 s70 s90 scompleted
bulk-140 s / 2 s74 s76 scompleted
bulk-150 s / 2 s76 s78 scompleted
bulk-160 s / 20 s78 s98 scompleted
bulk-170 s / 2 s84 s86 scompleted
bulk-180 s / 2 s86 s88 scompleted
bulk-190 s / 20 s88 s108 scompleted
bulk-200 s / 2 s90 s92 scompleted
Page 1 of 2
Tenant round robin: one-second samples after dispatch
TimeQueued / runningReady / startingRetiring / liveOldest waitCompleted / rejected
0 s21 / 33 / 00 / 30 s0 / 0
1 s22 / 33 / 00 / 31 s0 / 0
2 s21 / 33 / 00 / 32 s2 / 0
3 s21 / 33 / 00 / 33 s2 / 0
4 s20 / 33 / 00 / 34 s3 / 0
5 s21 / 33 / 00 / 35 s3 / 0
6 s22 / 33 / 00 / 36 s3 / 0
7 s22 / 33 / 00 / 37 s3 / 0
8 s22 / 33 / 00 / 38 s3 / 0
9 s23 / 33 / 00 / 39 s3 / 0
10 s24 / 33 / 00 / 310 s3 / 0
11 s24 / 33 / 00 / 311 s3 / 0
12 s24 / 33 / 00 / 312 s3 / 0
13 s25 / 33 / 00 / 313 s3 / 0
14 s26 / 33 / 00 / 314 s3 / 0
15 s26 / 33 / 00 / 315 s3 / 0
16 s26 / 33 / 00 / 316 s3 / 0
17 s27 / 33 / 00 / 317 s3 / 0
18 s28 / 33 / 00 / 318 s3 / 0
19 s28 / 33 / 00 / 319 s3 / 0
Page 1 of 13
Strict priority: job and clock trace
Strict priority: per-tenant outcomes
TenantCompleted / acceptedPending / rejectedP95 completed latencyP95 wait of started jobsOldest unstarted wait
bulk24 / 240 / 0110 s96 sNone waiting
interactive6 / 60 / 017 s15 sNone waiting
reports6 / 60 / 046 s26 sNone waiting
Strict priority: individual jobs
JobArrives / serviceStartsFinishesState at cutoff
bulk-10 s / 20 s0 s20 scompleted
bulk-20 s / 2 s0 s2 scompleted
bulk-30 s / 2 s0 s2 scompleted
bulk-40 s / 20 s4 s24 scompleted
bulk-50 s / 2 s46 s48 scompleted
bulk-60 s / 2 s48 s50 scompleted
bulk-70 s / 20 s50 s70 scompleted
bulk-80 s / 2 s64 s66 scompleted
bulk-90 s / 2 s66 s68 scompleted
bulk-100 s / 20 s66 s86 scompleted
bulk-110 s / 2 s68 s70 scompleted
bulk-120 s / 2 s70 s72 scompleted
bulk-130 s / 20 s70 s90 scompleted
bulk-140 s / 2 s72 s74 scompleted
bulk-150 s / 2 s74 s76 scompleted
bulk-160 s / 20 s76 s96 scompleted
bulk-170 s / 2 s86 s88 scompleted
bulk-180 s / 2 s88 s90 scompleted
bulk-190 s / 20 s90 s110 scompleted
bulk-200 s / 2 s90 s92 scompleted
Page 1 of 2
Strict priority: one-second samples after dispatch
TimeQueued / runningReady / startingRetiring / liveOldest waitCompleted / rejected
0 s21 / 33 / 00 / 30 s0 / 0
1 s22 / 33 / 00 / 31 s0 / 0
2 s21 / 33 / 00 / 32 s2 / 0
3 s21 / 33 / 00 / 33 s2 / 0
4 s20 / 33 / 00 / 34 s3 / 0
5 s21 / 33 / 00 / 35 s3 / 0
6 s22 / 33 / 00 / 36 s3 / 0
7 s22 / 33 / 00 / 37 s3 / 0
8 s22 / 33 / 00 / 38 s3 / 0
9 s23 / 33 / 00 / 39 s3 / 0
10 s24 / 33 / 00 / 310 s3 / 0
11 s24 / 33 / 00 / 311 s3 / 0
12 s24 / 33 / 00 / 312 s3 / 0
13 s25 / 33 / 00 / 313 s3 / 0
14 s26 / 33 / 00 / 314 s3 / 0
15 s26 / 33 / 00 / 315 s3 / 0
16 s26 / 33 / 00 / 316 s3 / 0
17 s27 / 33 / 00 / 317 s3 / 0
18 s28 / 33 / 00 / 318 s3 / 0
19 s28 / 33 / 00 / 319 s3 / 0
Page 1 of 13
Round robin + tenant cap: job and clock trace
Round robin + tenant cap: per-tenant outcomes
TenantCompleted / acceptedPending / rejectedP95 completed latencyP95 wait of started jobsOldest unstarted wait
bulk24 / 240 / 0190 s188 sNone waiting
interactive6 / 60 / 02 s0 sNone waiting
reports6 / 60 / 0100 s80 sNone waiting
Round robin + tenant cap: individual jobs
JobArrives / serviceStartsFinishesState at cutoff
bulk-10 s / 20 s0 s20 scompleted
bulk-20 s / 2 s20 s22 scompleted
bulk-30 s / 2 s22 s24 scompleted
bulk-40 s / 20 s24 s44 scompleted
bulk-50 s / 2 s44 s46 scompleted
bulk-60 s / 2 s46 s48 scompleted
bulk-70 s / 20 s48 s68 scompleted
bulk-80 s / 2 s68 s70 scompleted
bulk-90 s / 2 s70 s72 scompleted
bulk-100 s / 20 s72 s92 scompleted
bulk-110 s / 2 s92 s94 scompleted
bulk-120 s / 2 s94 s96 scompleted
bulk-130 s / 20 s96 s116 scompleted
bulk-140 s / 2 s116 s118 scompleted
bulk-150 s / 2 s118 s120 scompleted
bulk-160 s / 20 s120 s140 scompleted
bulk-170 s / 2 s140 s142 scompleted
bulk-180 s / 2 s142 s144 scompleted
bulk-190 s / 20 s144 s164 scompleted
bulk-200 s / 2 s164 s166 scompleted
Page 1 of 2
Round robin + tenant cap: one-second samples after dispatch
TimeQueued / runningReady / startingRetiring / liveOldest waitCompleted / rejected
0 s23 / 13 / 00 / 30 s0 / 0
1 s23 / 23 / 00 / 31 s0 / 0
2 s23 / 33 / 00 / 32 s0 / 0
3 s23 / 23 / 00 / 33 s1 / 0
4 s23 / 23 / 00 / 34 s1 / 0
5 s23 / 33 / 00 / 35 s1 / 0
6 s24 / 33 / 00 / 36 s1 / 0
7 s24 / 23 / 00 / 37 s2 / 0
8 s24 / 23 / 00 / 38 s2 / 0
9 s24 / 33 / 00 / 39 s2 / 0
10 s25 / 33 / 00 / 310 s2 / 0
11 s25 / 23 / 00 / 311 s3 / 0
12 s25 / 23 / 00 / 312 s3 / 0
13 s25 / 33 / 00 / 313 s3 / 0
14 s26 / 33 / 00 / 314 s3 / 0
15 s26 / 23 / 00 / 315 s4 / 0
16 s26 / 23 / 00 / 316 s4 / 0
17 s26 / 33 / 00 / 317 s4 / 0
18 s27 / 33 / 00 / 318 s4 / 0
19 s27 / 23 / 00 / 319 s5 / 0
Page 1 of 13

Aggregate capacity does not allocate service fairly

FIFO, job-level round robin, strict priority, and per-tenant concurrency limits allocate scarce worker slots differently. Compare pending work and rejected submissions alongside completion percentiles: a tenant that completes nothing has no reassuring latency percentile. Admission and scheduling are separate policies, and a finite trace can demonstrate lack of service without proving perpetual starvation.

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.
  • Bulk jobs arrive at the chosen spacing; every third bulk job is long. Interactive jobs are short and start arriving at second 1; reports are long and start at second 2, both using the quiet-tenant interval.
  • Priorities are interactive, reports, then bulk. The same trace runs through FIFO, job-round-robin, strict priority, and round-robin with a per-tenant running limit.