Open-source project
ixti/sidekiq-throttled avatar
ixti/sidekiq-throttled

sidekiq-throttled puts concurrency and rate limits on Sidekiq jobs

Concurrency and rate-limit throttling for Sidekiq

801 stars97 forksRubyMIT

At a glance

What is it?
The sidekiq-throttled gem adds two kinds of limit to a Sidekiq job class, a concurrency limit on how many run at once and a threshold limit on how many run in a period, with a requeue strategy that either pushes a blocked job straight back or schedules it for later. It suits applications that call a rate limited API and need the queue to absorb the overflow rather than the workers.
Who is it for?
Adopt sidekiq-throttled when a Sidekiq job class talks to something with a hard concurrency or rate limit, such as a third party API, and you would rather the queue absorbed the excess than have workers spin on retries. Do not adopt it if the pressure you need to relieve is a slow database rather than a rate limited endpoint, since the limits here are on job classes, not on connections.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Two different kinds of limit

The gem is described as concurrency and threshold throttling for Sidekiq, and the two words mean different things that a team often conflates. Concurrency is about how many jobs of a class are running at the same time, which matters when the resource is a shared thing with a small number of slots, such as a printing service or a legacy system that tolerates one session. Threshold is about how many jobs run in a window of time, which is what you need when the constraint is a rate limit expressed in calls per hour. The README's example job shows both declared side by side, allowing at most 10 concurrent jobs of the class and at most a thousand jobs processed within a one hour window, with a threshold that behaves like an allowance that refills over time.

One require, one include, one declaration

The integration is small. You add the gem to the Gemfile:

ruby
gem "sidekiq-throttled"

then run `bundle`, or install it yourself with `gem install sidekiq-throttled`. Somewhere in your application's bootstrap, for example `config/initializers/sidekiq.rb` in a Rails app, you require it:

ruby
require "sidekiq/throttled"

Then a job class includes the module and declares its limits:

ruby
class MyJob
  include Sidekiq::Job
  include Sidekiq::Throttled::Job

  sidekiq_options :queue => :my_queue

  sidekiq_throttle(
    # Allow maximum 10 concurrent jobs of this class at a time.
    concurrency: { limit: 10 },
    # Allow maximum 1K jobs being processed within one hour window.
    threshold: { limit: 1_000, period: 1.hour }
  )

  def perform
    # ...
  end
end

There is a naming detail worth knowing. `Sidekiq::Throttled::Job` is aliased as `Sidekiq::Throttled::Worker`, so a codebase that still uses the `Sidekiq::Worker` naming convention can include the alias instead, which keeps the file consistent with the rest of its job classes.

Requeue: put it back now, or schedule it

What happens to a job that hits a limit is a decision you make, and the README explains both options and their costs. The default requeue strategy is `:enqueue`, which puts jobs immediately back on the queue if they are being limited, with a potential cooldown period. The README says this is often appropriate, but that in some situations it may cause the system to repeatedly dequeue and requeue the same job, causing excessive Redis CPU usage. The alternative is `:schedule`, which schedules the work for the future. The README is candid that this can be less appropriate for highly concurrent jobs, but that it may be a good way to reduce Redis load when the number of jobs to be processed is modest. The choice can be set globally with `config.default_requeue_options = { with: :schedule }`, or per job:

ruby
  sidekiq_throttle(
    # Allow 5 jobs to processed within 1 minute, using the 
    threshold: { limit: 5, period: 1.minute },
    requeue: { with: :schedule }
  )

and a job can also be requeued to a different queue with `requeue: { to: :other_queue, with: :schedule }`, which is useful when the blocked work should not sit in front of unrelated jobs.

The cooldown manager stops a queue being polled

There is a second mechanism underneath the limits, and it is the one most likely to surprise you. The configuration block has a `cooldown_period`, a period in seconds to exclude a queue from polling in case it returned a given amount of throttled jobs in a row, and a `cooldown_threshold`, the amount of throttled jobs in a row that triggers the exclusion, with defaults of 1.0 second and 100 jobs. Setting the period to nil disables the cooldown manager completely. The README's warning explains the effect with a concrete case. If a queue contains a thousand jobs in a row that will be throttled, the cooldown kicks in ten times in a row, meaning it takes ten seconds before all those jobs are put back at the end of the queue and you actually start processing other jobs. The tuning note is that adjusting the threshold and the period also affects the load on your Redis server, so the two settings are a single trade-off rather than two independent knobs.

The middleware is injected, and you can reorder it

Sidekiq::Throttled relies on a bundled middleware, `Sidekiq::Throttled::Middlewares::Server`, and the middleware is automatically injected when you require `sidekiq/throttled`, which is why the earlier require line matters beyond loading constants. The README notes that in rare cases this automatic injection causes an issue, and that you can then change the middleware order manually:

ruby
Sidekiq.configure_server do |config|
  # ...

  config.server_middleware do |chain|
    chain.prepend(Sidekiq::Throttled::Middlewares::Server)
  end
end

The reference to Sidekiq's own middleware chain file is included for the reader who needs to know what position the entry takes. The practical takeaway is that the ordering of the server middleware is part of the contract with this gem, and that if a job's behaviour looks wrong under load, the middleware order is one of the first things to check.

Observers and limits computed at fetch time

Two extension points make the gem usable in a real application. The observer is a callable passed with the `:observer` option, and it is called on throttling:

ruby
class MyJob
  include Sidekiq::Job
  include Sidekiq::Throttled::Job

  MY_OBSERVER = lambda do |strategy, *args|
    # do something
  end

  sidekiq_options queue: :my_queue

  sidekiq_throttle(
    concurrency: { limit: 10 },
    threshold:   { limit: 100, period: 1.hour },
    observer:    MY_OBSERVER
  )

  def perform(*args)
    # ...
  end
end

The observer receives `strategy, *args`, where the strategy is the symbol `:concurrency` or `:threshold` and the remaining arguments are the ones passed to the job. The second extension point is dynamic throttling through the `:key_suffix` option, which lets a limit be per user rather than per class, and the README also allows the limit and the period themselves to be procs, evaluated at the time the job is fetched and receiving the same arguments as the job, so a VIP user can be allowed a thousand concurrent jobs while everyone else gets ten.

A tab in the Sidekiq web UI, and the project around it

There is a web interface. To add a Throttled tab to your Sidekiq web dashboard, you require it during your application initialisation:

ruby
require "sidekiq/throttled/web"

That gives operators a view of what is being throttled, which pairs well with the cooldown manager since both are about understanding why a queue is not draining. The repository layout matches a gem that takes a real project. There is `lib/` for the library, `spec/` with the RSpec configuration in `.rspec` and coverage settings in `.simplecov`, a `demo/` directory with its own `Gemfile`, `Procfile`, `config.ru` and `app.rb` for trying the gem locally, a `web/` directory for the dashboard part, and the usual project furniture in `Rakefile`, `Guardfile`, `Appraisals`, `CHANGES.md` and `rubocop/`. The licence is MIT, in `LICENSE.txt`, and the repository is not archived, with the last push on 2026-10-22, though there are no GitHub releases, so the version on rubygems.org is the reference point.

Editorial conclusion

Adopt sidekiq-throttled when a Sidekiq job class talks to something with a hard concurrency or rate limit, such as a third party API, and you would rather the queue absorbed the excess than have workers spin on retries. Do not adopt it if the pressure you need to relieve is a slow database rather than a rate limited endpoint, since the limits here are on job classes, not on connections. Verify first which requeue strategy you want, because the default puts a blocked job immediately back on the queue and can cause repeated dequeue and requeue cycles against Redis, and read the cooldown settings, since the default behaviour of excluding a queue from polling after a run of throttled jobs is the part that surprises people.

Frequently asked questions

What is the difference between concurrency and threshold throttling in sidekiq-throttled?

Concurrency limits how many jobs of a class run at the same time, through `concurrency: { limit: 10 }`, while threshold limits how many run inside a period, through `threshold: { limit: 1_000, period: 1.hour }`. The first suits a resource with a fixed number of slots, the second a rate limit.

What happens when a job hits its limit?

The default requeue strategy is `:enqueue`, which puts the job immediately back on the queue with a potential cooldown period, and the README warns that this can cause repeated dequeue and requeue cycles and excessive Redis CPU usage. The alternative `:schedule` schedules the work for the future instead.

What do the cooldown settings do?

The `cooldown_threshold` is the number of throttled jobs in a row that excludes a queue from polling, and `cooldown_period` is how long that exclusion lasts, with defaults of 100 jobs and 1.0 second. Setting the period to nil disables the cooldown manager, and the README notes that tuning them also affects the load on your Redis server.

Can sidekiq-throttled limit jobs per user rather than per class?

Yes. The `:key_suffix` option takes a proc, and the limit and the period themselves can also be procs that are evaluated when the job is fetched and receive the job's arguments, so different users can have different limits.

Official sources

  1. Issues
  2. ixti/sidekiq-throttled on GitHub
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ixti-sidekiq-throttled.svg)](https://hysenlabs.com/projects/ixti-sidekiq-throttled)

Was this useful?