Sidekiq::Throttler is a middleware for Sidekiq that adds the ability to rate limit job execution on a per-worker basis.
Sidekiq::Throttler supports Sidekiq versions 2 and 3 and is actively tested against Ruby versions 2.0.0, 2.1, and 2.2.
Add this line to your application's Gemfile:
gem 'sidekiq-throttler'
And then execute:
$ bundle
Or install it yourself as:
$ gem install sidekiq-throttler
In a Rails initializer or wherever you've configured Sidekiq, add Sidekiq::Throttler to your server middleware:
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add Sidekiq::Throttler
end
end
Sidekiq::Throttler defaults to in-memory storage of job execution times. If
you have multiple worker processes, or frequently restart your processes, this
will be unreliable. Instead, specify the :redis
storage option:
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add Sidekiq::Throttler, storage: :redis
end
end
In a worker, specify a threshold (maximum jobs) and period for throttling:
class MyWorker
include Sidekiq::Worker
sidekiq_options throttle: { threshold: 50, period: 1.hour }
def perform(user_id)
# Do some heavy API interactions.
end
end
In the above example, when the number of executed jobs for the worker exceeds 50 in an hour, remaining jobs will be delayed.
By default, each worker has its own key for throttling. For example:
class FooWorker
include Sidekiq::Worker
sidekiq_options throttle: { threshold: 50, period: 1.hour }
# ...
end
class BarWorker
include Sidekiq::Worker
sidekiq_options throttle: { threshold: 50, period: 1.hour }
# ...
end
Even though FooWorker
and BarWorker
use the same throttle options, they are
treated as different groups. To have multiple workers with shared throttling,
the :key
options can be used:
sidekiq_options throttle: { threshold: 50, period: 1.hour, key: 'foobar' }
Any jobs using the same key, regardless of the worker will be tracked under the same conditions.
Each option (:threshold
, :period
, and :key
) accepts a static value but can
also accept a Proc
that's called each time a job is processed.
If throttling is per-user, for example, you can specify a Proc
for key
which
accepts the arguments passed to your worker's perform
method:
sidekiq_options throttle: { threshold: 20, period: 1.day, key: ->(user_id){ user_id } }
In the above example, jobs are throttled for each user when they exceed 20 in a day.
Thresholds can be configured based on the arguments passed to your worker's perform
method,
similar to how the key
option works:
sidekiq_options throttle: { threshold: ->(user_id, rate_limit) { rate_limit }, period: 1.hour, key: ->(user_id, rate_limit){ user_id } }
In the above example, jobs are throttled for each user when they exceed the rate limit provided in the message. This is useful in cases where each user may have a different rate limit (ex: interacting with external APIs)
In this contrived example, our worker is limited to 9 thousand jobs every 10 minutes. However, on Tuesdays limit jobs to 9 thousand every 15 minutes:
sidekiq_options throttle: { threshold: 9000, period: ->{ Date.today.tuesday? ? 15.minutes : 10.minutes } }
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
MIT Licensed. See LICENSE.txt for details.