Set Current on all jobs

I recently needed to log the specific users, who use various external services. But a lot of these services are used through background jobs, losing any attributes set on the Current object, which we use to hold the current user.

So I had to go through every job - and every place we called them - and add a user param.

I did not want to do that. Instead what I ended up doing was this:

class ApplicationJob < ActiveJob::Base
  def serialize
    super.merge("current_user_id" => Current.user.id)
  end

  def deserialize(job_data)
    super

    if job_data.key?("current_user_id")
      Current.user = User.find(job_data["current_user_id"])
    else
      Current.user = fallback_user
    end
  end
  
  private
  
  def fallback_user
	  # find the fallback user
  end
end

When the serialize method is called, we are still in a context, where we have access to the Current object - so we serialize the user id.

When the job is picked up by the queue adapter, we can hook into the deserialization process and setup the Current object.

These methods are only called when using SomeJob.perform_later. Jobs performed with perform_now will be running on the same thread and therefore have access to Current without needing to do more.

If you have more things, that you need to set on current, you can call Current.attributes in the serialize method to get a hash of all the data in Current. But beware - the data might not be json compatible, which Sidekiq dislikes. Furthermore sensitive data might be included - make sure to filter the attributes for anything, that should not be persisted in the queue, like password hashes, tokens etc.

See https://api.rubyonrails.org/classes/ActiveJob/Core.html#method-i-deserialize for more