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