<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/fair-by-design-orchestrating-background-jobs-in-ruby-martian-chronicles-evil-martians-team-blog-piyszlqky" -->

---
title: Fair by design: orchestrating background jobs in...
description: When multiple tenants share a background job queue, greedy tenants can monopolize workers and degrade quality of service for everyone else. This deep-dive...
canonical: https://daily.dev/posts/fair-by-design-orchestrating-background-jobs-in-ruby-martian-chronicles-evil-martians-team-blog-piyszlqky
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Fair by design: orchestrating background jobs in Ruby—Martian Chronicles, Evil Martians’ team blog | daily.dev
og:description: When multiple tenants share a background job queue, greedy tenants can monopolize workers and degrade quality of service for everyone else. This deep-dive...
og:url: https://daily.dev/posts/fair-by-design-orchestrating-background-jobs-in-ruby-martian-chronicles-evil-martians-team-blog-piyszlqky
og:image: https://api.daily.dev/og/posts/PIYszlqkY.png
og:image:alt: Fair by design: orchestrating background jobs in Ruby—Martian Chronicles, Evil Martians’ team blog
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Fair by design: orchestrating background jobs in Ruby—Martian Chronicles, Evil Martians’ team blog

**[Martian Chronicles](https://daily.dev/sources/evilmartians)** · 23 min read · 0 upvotes · 0 comments

## Summary

When multiple tenants share a background job queue, greedy tenants can monopolize workers and degrade quality of service for everyone else. This deep-dive examines four strategies for achieving fair scheduling in Ruby: shuffle-sharding (workload isolation via overlapping shard subsets), interruptible iteration (time-bounded resumable jobs using Shopify's job-iteration gem), throttling (leaky-bucket detection routing excess jobs to a slow queue), and per-tenant queues with a custom scheduler (a planner that promotes jobs from per-tenant virtual queues into the main queue based on a fairness policy). Each of Sidekiq, Sidekiq Pro, Solid Queue, and GoodJob is analyzed for dynamic queue support and weighted polling. The author recommends starting with the custom scheduler approach for its flexibility, falling back to the other strategies based on workload shape and scale.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://evilmartians.com/chronicles/fair-by-design-orchestrating-background-jobs-in-ruby>

## Questions this post answers

### Does Sidekiq support dynamic per-tenant queues for fair scheduling?

No, Sidekiq workers subscribe to a fixed, static queue list defined at process startup, so tenant queues cannot be added or removed while the process is running. This makes it hard to implement fair scheduling for a large, dynamic set of tenants, even though its BRPOP-based polling with shuffled equal weights already resembles a fair scheduler for a static queue list.

_Teams weighing Sidekiq against alternatives for multi-tenant fairness can track these trade-offs on daily.dev._

### Why doesn't Sidekiq Pro's reliable job queue support dynamic queues either?

Sidekiq Pro trades the single blocking BRPOP call for per-worker LMOVE calls that move jobs into worker-specific in-progress queues so crashed jobs aren't lost, but this requires polling each tenant queue individually and non-blocking, which scales poorly as the number of queues grows. Like open source Sidekiq, it still relies on a static, pre-configured queue list, so dynamic per-tenant queues were never supported.

_Developers picking a reliable job processor for multi-tenant workloads can weigh this reliability-versus-scalability trade-off via daily.dev._

### Which Ruby background job processors support dynamic queue names for multi-tenant workloads?

Solid Queue supports dynamic queues, letting a worker process all queues matching a pattern like tenant_*, unlike Sidekiq and Sidekiq Pro which require a fixed queue list at startup. However, Solid Queue lacks weighted queue polling, returning queues in database order rather than shuffled or weighted, so achieving fairness still requires additional work. GoodJob, backed by PostgreSQL with advisory locks, supports neither dynamic nor weighted queues.

_Evaluating Solid Queue, GoodJob, or Sidekiq for tenant isolation gets easier when comparisons like this surface on daily.dev._

## Similar posts on daily.dev

- [GitHub - nicolasva/solid-jobs](https://daily.dev/posts/github---nicolasva-solid-jobs-3psnafm9f) · Ruby Flow · 0 upvotes · 0 comments
- [GoodJob, Solid Queue, Sidekiq, Active Job, in 2026](https://daily.dev/posts/goodjob-solid-queue-sidekiq-active-job-in-2026-yvn44jn5s) · RUBYLAND · 0 upvotes · 0 comments
- [Everything you should know about Background Jobs with ActiveJob](https://daily.dev/posts/everything-you-should-know-about-background-jobs-with-activejob-uxyudjznl) · The Miners · 0 upvotes · 0 comments
- [Why Gusto hired Evil Martians for Sidekiq infrastructure—Martian Chronicles, Evil Martians’ team blog](https://daily.dev/posts/why-gusto-hired-evil-martians-for-sidekiq-infrastructure-martian-chronicles-evil-martians-team-blo-e2ddm8ahv) · Martian Chronicles · 2 upvotes · 1 comments
- [Enhancing job reliability with Sidekiq Pro's super fetch strategy](https://daily.dev/posts/enhancing-job-reliability-with-sidekiq-pro-s-super-fetch-strategy-f3cx6mko3) · thoughbot · 0 upvotes · 0 comments

---

Tags: [#ruby](https://daily.dev/tags/ruby), [#multi-tenancy](https://daily.dev/tags/multi-tenancy)

[View this post on daily.dev](https://daily.dev/posts/fair-by-design-orchestrating-background-jobs-in-ruby-martian-chronicles-evil-martians-team-blog-piyszlqky)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Fair by design: orchestrating background jobs in Ruby—Martian Chronicles, Evil Martians’ team blog","url":"https://daily.dev/posts/fair-by-design-orchestrating-background-jobs-in-ruby-martian-chronicles-evil-martians-team-blog-piyszlqky","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/fair-by-design-orchestrating-background-jobs-in-ruby-martian-chronicles-evil-martians-team-blog-piyszlqky"},"datePublished":"2026-08-11T16:35:50.367Z","dateModified":"2026-09-14T08:20:08.245Z","description":"When multiple tenants share a background job queue, greedy tenants can monopolize workers and degrade quality of service for everyone else. This deep-dive...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/959afc066318590b7d368701d4f58e8a?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/959afc066318590b7d368701d4f58e8a?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Martian Chronicles","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Martian Chronicles","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/6334c9de96a7414ebbf4b7667ba572c5","url":"https://daily.dev/sources/evilmartians"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/fair-by-design-orchestrating-background-jobs-in-ruby-martian-chronicles-evil-martians-team-blog-piyszlqky","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"ruby,multi-tenancy","timeRequired":"PT23M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Martian Chronicles","item":"https://daily.dev/sources/evilmartians"},{"@type":"ListItem","position":3,"name":"Fair by design: orchestrating background jobs in Ruby—Martian Chronicles, Evil Martians’ team blog"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/fair-by-design-orchestrating-background-jobs-in-ruby-martian-chronicles-evil-martians-team-blog-piyszlqky#faq","mainEntity":[{"@type":"Question","name":"Does Sidekiq support dynamic per-tenant queues for fair scheduling?","acceptedAnswer":{"@type":"Answer","text":"No, Sidekiq workers subscribe to a fixed, static queue list defined at process startup, so tenant queues cannot be added or removed while the process is running. This makes it hard to implement fair scheduling for a large, dynamic set of tenants, even though its BRPOP-based polling with shuffled equal weights already resembles a fair scheduler for a static queue list. Teams weighing Sidekiq against alternatives for multi-tenant fairness can track these trade-offs on daily.dev."}},{"@type":"Question","name":"Why doesn't Sidekiq Pro's reliable job queue support dynamic queues either?","acceptedAnswer":{"@type":"Answer","text":"Sidekiq Pro trades the single blocking BRPOP call for per-worker LMOVE calls that move jobs into worker-specific in-progress queues so crashed jobs aren't lost, but this requires polling each tenant queue individually and non-blocking, which scales poorly as the number of queues grows. Like open source Sidekiq, it still relies on a static, pre-configured queue list, so dynamic per-tenant queues were never supported. Developers picking a reliable job processor for multi-tenant workloads can weigh this reliability-versus-scalability trade-off via daily.dev."}},{"@type":"Question","name":"Which Ruby background job processors support dynamic queue names for multi-tenant workloads?","acceptedAnswer":{"@type":"Answer","text":"Solid Queue supports dynamic queues, letting a worker process all queues matching a pattern like tenant_*, unlike Sidekiq and Sidekiq Pro which require a fixed queue list at startup. However, Solid Queue lacks weighted queue polling, returning queues in database order rather than shuffled or weighted, so achieving fairness still requires additional work. GoodJob, backed by PostgreSQL with advisory locks, supports neither dynamic nor weighted queues. Evaluating Solid Queue, GoodJob, or Sidekiq for tenant isolation gets easier when comparisons like this surface on daily.dev."}}]}
```

