This is a genuine discrete-time simulation, not an analytic formula plotted as a curve. Every tick, each idle worker pulls one notification off the shared queue and processes it for 1 / per-worker-rate seconds. When processing finishes, the worker must acquire a token from a single shared token bucket (the push-gateway rate limit) before the notification counts as delivered โ if no token is free, the worker holds the finished packet and blocks until one is.
per tick:
refill bucket by rateLimit * dt (cap 1 token)
finish any worker whose processing timer hit 0 -> "waiting for token"
waiting workers with a free token -> deliver, consume token
idle workers with backlog -> pull next item, start processing
theoretical crossover: W* ≈ rateLimit / perWorkerRate
below W*: total time ≈ N / (W * perWorkerRate) (linear speedup)
at/above W*: total time ≈ N / rateLimit (gateway-bound plateau)
The scaling curve on the left is built by re-running this exact tick loop, with a fresh simulated state, once for every worker count from 1 up to 16 โ the "genuinely computed" result, not the closed-form line above (that line is only the theoretical prediction the simulation is checked against). At low worker counts every added worker is fully used, so completion time falls roughly in proportion to W. Once W ยท per-worker-rate passes the gateway's rateLimit, extra workers spend their time waiting for a token instead of processing, and the curve flattens โ the plateau always sits at worker count ≈ rateLimit / per-worker-rate, which you can verify by dragging the rate-limit or per-worker-rate sliders and watching the flattening point shift.