The Sidekiq Argument

tl;dr A Sidekiq worker’s perform method should only ever take a single hash parameter.

Writing a Sidekiq worker is blessedly simple: include the Sidekiq::Worker module, and write a perform method. Heck, Sidekiq doesn’t even impose any sort of restrictions on the arguments to your perform method. Allow me to gently suggest a restriction you should adopt for your Sidekiq workers: #perform should accept a single hash parameter. Even in the simple case where you have a single parameter, using a hash will save you time and effort in the long run.

Do this:

class MaintainableWorker
  include Sidekiq::Worker

  def perform(opts)
    thing = ThingRegistry.lookup(id: opts["id"])
    thing.do_something! if thing

Not this:

class HotMessWorker
  include Sidekiq::Worker

  def perform(id)
    thing = ThingRegistry.lookup(id)
    thing.do_something! if thing

This makes the workers more amenable to change. If you’re trying to get to zero-downtime deploys, you don’t want the signature of a method to change. The previous version of the code could schedule a job with the the old arguments, but a worker running the new version of the code might be the one to pull the job off the queue. There are other ways to approach this, like making new arguments optional, but that can lead to a crufty method signature over time. Things get even trickier if you want to remove a parameter. Additionally, I like having a uniform interface when scheduling jobs. It’s just a little less cognitive overhead when I don’t have to worry about how the parameters are arranged. (Maybe this is why I’ve moved heavily towards named parameters in much of my Ruby code!)

It’s much less painful if you just start with a hash. New parameters are simply new keys; old parameters simply don’t get passed any longer.

This doesn’t remove the responsibility for coding defensively. If you’re adding a new parameter, be sure to handle the case when it hasn’t been provided (at least until the changed code has been out for a while). And of course the usual Sidekiq best practice of passing JSON-serializable parameters still holds; pass a user ID, not an instance of a User object.

Questions? Comments? Contact me!

Tools Used