Upgrade to PRO for Only $50/Yearโ€”Limited-Time Offer! ๐Ÿ”ฅ

Prioritization justice: lessons from making bac...

Prioritization justice: lessons from making background jobs fair atย scale

Are you treating your users fairly? They could be stuck in the queue while a greedy user monopolizes resources. And you might not even know it! In this talk, Alexander Baygeldin, backend engineer at Evil Martians, is going to show if itโ€™s time for you to take background job prioritization seriouslyโ€”and how to make it fair for all users.

Avatar for Alexander Baygeldin

Alexander Baygeldin

September 22, 2025
Tweet

More Decks by Alexander Baygeldin

Other Decks in Programming

Transcript

  1. ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿ• ๐Ÿ• ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿงข ๐Ÿง‘๐Ÿณ

    ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข part-time chefs
  2. ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿ• ๐Ÿ• ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿงข ๐Ÿง‘๐Ÿณ

    ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข ๐Ÿง‘๐Ÿณ ๐Ÿงข part-time chefs At some point improving Quality of Service at more operational cost leads to diminishing returns
  3. G = n โˆ‘ i=1 n โˆ‘ j=1 xi โˆ’

    xj 2n2 ยฏ x = n โˆ‘ i=1 n โˆ‘ j=1 xi โˆ’ xj 2n n โˆ‘ i=1 xi ๐’ฅ (x1 , x2 , โ€ฆ, xn ) = (โˆ‘n i=1 xi )2 n โ‹… โˆ‘n i=1 xi 2 = x2 x2 = 1 1 + ฬ‚ cv 2 Jain's index? Gini index? Some other guy's index?
  4. How do we know if we're not? โ˜‘ FIFO queue

    โ˜‘ High latency โ˜‘ Greedy users Are we OK?
  5. ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ LMOVE queue:tenant_1 queue:sq|<worker ID>|tenant_1 RIGHT LEFT LMOVE

    queue:tenant_2 queue:sq|<worker ID>|tenant_2 RIGHT LEFT ... LMOVE queue:tenant_N queue:sq|<worker ID>|tenant_N RIGHT LEFT worker's "in-progress" queues per-tenant queues
  6. ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ Solid Queue SELECT job_id FROM solid_queue_ready_executions WHERE

    queue_name = 'tenant_N' ORDER BY priority ASC, job_id ASC LIMIT ? FOR UPDATE SKIP LOCKED;
  7. ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ GoodJob ๐Ÿ‘ WITH rows AS MATERIALIZED (

    SELECT id, active_job_id FROM good_jobs WHERE queue_name = 'tenant_N' AND (<more filters>) ORDER BY priority DESC NULLS LAST, created_at ASC LIMIT ? ) SELECT id FROM rows WHERE pg_try_advisory_lock(<lock hash based on active_job_id>) LIMIT 1
  8. (with what we have) 1. Shu ff l e-sharding 2.

    Interruptible iteration 3. Throttling 4. Per-tenant queues Let's fix this!
  9. ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ Alex ๐Ÿ• A to I J to

    R S to Z Amy ๐Ÿ• Joe ๐Ÿ• Sam ๐Ÿ• Sam ๐Ÿ• Amy ๐Ÿ•
  10. ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ Alex ๐Ÿ• A to I J to

    R S to Z Amy ๐Ÿ• Joe ๐Ÿ• Sam ๐Ÿ• Sam ๐Ÿ• Amy ๐Ÿ•
  11. ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ A to I J to R S

    to Z Amy ๐Ÿ• Amy ๐Ÿ• ๐Ÿ’ค Sam ๐Ÿ•
  12. ๐Ÿง‘๐Ÿณ ๐Ÿท Pentagon ๐Ÿ• ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ A to I J

    to R S to Z Amy ๐Ÿ• Amy ๐Ÿ• Sam ๐Ÿ• ๐Ÿท Pentagon ๐Ÿ•
  13. ๐Ÿง‘๐Ÿณ ๐Ÿท Pentagon ๐Ÿ• ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ A to I J

    to R S to Z Amy ๐Ÿ• Amy ๐Ÿ• Sam ๐Ÿ• ๐Ÿท Pentagon ๐Ÿ•
  14. ๐Ÿง‘๐Ÿณ ๐Ÿท Pentagon ๐Ÿ• ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ A to I J

    to R S to Z Amy ๐Ÿ• ๐Ÿท Pentagon ๐Ÿ• ๐Ÿ’ค Joe ๐Ÿ•
  15. Shuffle-sharding (tl;dr: good when you have enough workload to fi

    ll all shards) No hogging? No, but it's <number of shards> times less likely. Perfectly fair? No, but it a ff ects fewer people when it's not fair. Full resource utilization? Noโ€”underutilization is possible with too many shards. Does it scale? Yes, but it needs at least one worker per shard.
  16. Interruptible iteration (tl;dr: good when the workload comes in large

    batches) No hogging? Noโ€”it could happen if one tenant enqueues multiple batches. Perfectly fair? Noโ€”it stops being fair when someone hogs the queue. Full resource utilization? Yes, but <queue size> must be greater than <worker count>. Does it scale? Yesโ€”using cursors to track progress is cheap.
  17. ๐Ÿชฃ ๐Ÿšฟ ๐Ÿ•ณ ๐Ÿ’ง ๐Ÿ’ง ๐Ÿ’ง ๐Ÿ’ง ๐Ÿ’ง ๐Ÿ’ง ๐Ÿ’ง

    ๐Ÿ’ง ๐Ÿ’ง over time, the bucket leaks allowing further orders bucket has a limited capacity each new order fi lls the bucket
  18. ๐Ÿชฃ ๐Ÿšฟ ๐Ÿ•ณ ๐Ÿ’ง ๐Ÿ’ง ๐Ÿ’ง ๐Ÿ’ง ๐Ÿ’ง ๐Ÿ’ง ๐Ÿ’ง

    ๐Ÿ’ง ๐Ÿ’ฆ ๐Ÿ’ฆ uh-oh, over fl ow! over time, the bucket leaks allowing further orders bucket has a limited capacity each new order fi lls the bucket
  19. ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿ• ๐Ÿ• ๐Ÿ• ๐Ÿ• ๐ŸŽฒ default queue

    (80% chance to be processed) throttled queue (20% chance to be processed) ๐Ÿ•
  20. Throttling (tl;dr: good when the workload is well distributed over

    time) No hogging? Yesโ€”everyone will get at least a little work done. Perfectly fair? Noโ€”especially if the workload is bursty by nature. Full resource utilization? Yes, but it requires weighted queues support. Does it scale? Yesโ€”especially with leaky buckets.
  21. ๐Ÿ• ๐Ÿ• ๐Ÿ• ๐ŸŽฒ ๐Ÿ• ๐Ÿ• ๐Ÿ• ๐Ÿ• ๐Ÿ• ๐Ÿง‘๐Ÿณ

    ๐Ÿง‘๐Ÿณ ๐Ÿง‘๐Ÿณ ๐Ÿ“’ ๐Ÿ• ๐Ÿ• ๐Ÿ• ๐Ÿง™
  22. Per-tenant queues + custom scheduler (tl;dr: good when the workload

    is heavy enough to forget about the bottleneck) No hogging? Yesโ€”it's basically communism. Perfectly fair? Yesโ€”as fair as you care to make it. Full resource utilization? Yesโ€”with zero changes to the underlying infra. Does it scale? It depends... on how e ff i cient your scheduler is.
  23. (where fairness matter) โœจ AI work fl ows * โฌ‡

    Data imports ๐Ÿ–ผ Media processing ๐Ÿ“Š Reports generation Examples! ... and more! ` * less so with async-job
  24. So, which one? Shu ff l e- sharding Interruptible iteration

    Throttling Per-tenant queues No hogging? โŒ โŒ โœ… โœ… Perfectly fair? โŒ โŒ โŒ โœ… Full resource utilization? ๐ŸŸง ๐ŸŸง โœ… โœ… Does it scale? โœ… โœ… โœ… ๐ŸŸง
  25. (part 2) โ€ข Workload Isolation with Queue Sharding (by Mike

    Perham) โ€ข Workload Isolation Using Shu ff l e- Sharding (by Colm MacCรกrthaigh) Resources
  26. (part 3) โ€ข job-iteration gem (from Shopify) โ€ข Sidekiq Iterable

    Jobs: With Great Power.... (by Jon Sully) โ€ข Active Job Continuations Resources
  27. (part 4) โ€ข โ€œFairโ€ multi-tenant prioritization of Sidekiq jobsโ€”and our

    gem for it! (by Andrey Novikov) โ€ข The unreasonable e ff ectiveness of leaky buckets (and how to make one) (by Julik Tarkhanov) Resources