Sidekiq powers our background processing needs at AngelList. As we introduced Sidekiq in a legacy codebase and it started to handle significant job throughput, we developed a number of utilities to make working with Sidekiq easier that we'd love to share.
Adds support for automatically serializing and deserializing additional argument types for your workers:
Class
Symbol
(both by themselves and as hash keys)ActiveSupport::HashWithIndifferentAccess
To use this utility, you need to include the client and server middlewares. Be sure to include the client middleware on the server as well.
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add ::SidekiqUtils::Middleware::Server::AdditionalSerialization
end
config.client_middleware do |chain|
chain.add ::SidekiqUtils::Middleware::Client::AdditionalSerialization
end
end
Sidekiq.configure_client do |config|
config.client_middleware do |chain|
chain.add ::SidekiqUtils::Middleware::Client::AdditionalSerialization
end
end
sidekiq-unique-jobs will fail to properly determine job uniqueness if you don't hook the middlewares in the correct order. If you use both sidekiq-unique-jobs and the additional serialization utility, be sure to hook your middlewares in the following way:
Sidekiq.configure_server do |config|
# unwrap arguments first
config.server_middleware do |chain|
chain.add ::SidekiqUtils::Middleware::Server::AdditionalSerialization
end
# then determine unique jobs
SidekiqUniqueJobs.configure_server_middleware
# first determine uniqueness
SidekiqUniqueJobs.configure_client_middleware
# then wrap arguments
config.client_middleware do |chain|
chain.add ::SidekiqUtils::Middleware::Client::AdditionalSerialization
end
end
Sidekiq.configure_client do |config|
# first determine uniqueness
SidekiqUniqueJobs.configure_client_middleware
# then wrap arguments
config.client_middleware do |chain|
chain.add ::SidekiqUtils::Middleware::Client::AdditionalSerialization
end
end
Adds an easy ability to divert jobs added within a block to a lower-priority queue. This is useful, for example, in cron jobs. All jobs added within the block will be added to the low
queue instead of their default queue.
Sidekiq.configure_server do |config|
config.client_middleware do |chain|
chain.add SidekiqUtils::Middleware::Client::Deprioritize
end
end
Sidekiq.configure_client do |config|
config.client_middleware do |chain|
client_middlewares.each do |middleware|
chain.add SidekiqUtils::Middleware::Client::Deprioritize
end
end
end
SidekiqUtils::Deprioritize.workers(SolrIndexWorker) do
10_000.times do
# these will all go to the `low` queue
SolrIndexWorker.perform_async(User, rand(10_000))
end
end
A simple tool to inspect and manipulate Sidekiq queues from the console:
> SidekiqUtils::EnqueuedJobsHelper.counts
=> {"default"=>{}, "high"=>{"AlgoliaIndexWorker[JobProfile]"=>1}, "low"=>{"AlgoliaIndexWorker[JobProfile]"=>1}}
> SidekiqUtils::EnqueuedJobsHelper.delete(queue: 'low', job_class: 'AlgoliaIndexWorker', first_argument: JobProfile)
# first_argument is optional
Lots of jobs become moot when a record cannot be found; however, because Sidekiq is very fast and it's easy to forget to enqueue jobs in after_commit
hooks, sometimes the record isn't found simply because the transaction in which it was inserted has not been committed yet. This will retry a find_optional
call exactly once after 30 seconds if the record cannot be found.
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add SidekiqUtils::Middleware::Server::FindOptional
end
end
class SolrIndexWorker
include Sidekiq::Worker
def perform(user_id)
user = find_optional(User, user_id)
end
end
This will monitor queue latency and report to Slack channels if the latency exceeds the configured threshold.
Create a config/sidekiq_utils.yml
file in your project:
repeat_alert_every: 60 # repeat identical alerts every x minutes
alert_thresholds: # in minutes
default: 10
high: 5
low: 60
slack:
username: 'Sidekiq alerts'
icon: 'alarm_clock'
team: 'foobar'
token: 'xxx'
channels_to_alert:
- "#devops-alerts"
- "#sidekiq-alerts"
Simply call SidekiqUtils::LatencyAlert.check!
at regular intervals.
This will keep track of how many jobs of which worker class have run in the past week, as well as when it was last run.
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add SidekiqUtils::Middleware::Server::ThroughputMonitor
end
end
Sidekiq::Web.register SidekiqUtils::WebExtensions::ThroughputMonitor
Sidekiq::Web.tabs["Throughput"] = "throughput"
This will add a "Throughput" tab to your Sidekiq admin which will display job throughput information.