Sidekiq任务中默认传递current_user的实现方案咨询
Great approach using Sidekiq middleware to handle this! You're halfway there with the server middleware—let's fill in the gaps and add a client middleware to automatically inject the user info so you don't have to pass it every time.
Step 1: Complete the Server Middleware
First, let's finish your server middleware to properly set Thread.current[:current_user] from the job args. Assuming you're passing a user ID (or a serialized user reference), here's how to refine it:
# app/middleware/sidekiq_server_middleware.rb class SidekiqServerMiddleware def call(_worker, job, _queue) set_current_user(job['args']) yield ensure # Critical: Clear thread-local data after job runs to prevent cross-job contamination Thread.current[:current_user] = nil end private def set_current_user(args) last_arg = args.last return unless last_arg.is_a?(Hash) && last_arg[:current_user_id] # Fetch the user from the database using the stored ID Thread.current[:current_user] = User.find_by(id: last_arg[:current_user_id]) end end
The ensure block is non-negotiable here—it guarantees we clean up the thread-local variable, so subsequent jobs don't accidentally inherit the previous user's context.
Step 2: Add a Client Middleware to Auto-Inject current_user
Now, let's create a client middleware that automatically adds the current user's ID to job args whenever you enqueue a job (but only if current_user exists in the request context):
# app/middleware/sidekiq_client_middleware.rb class SidekiqClientMiddleware def call(_worker_class, job, _queue, _redis_pool) # Check if we're in a context where current_user is available (like a Rails controller) if defined?(current_user) && current_user.present? # Append the user ID as a hash to make it easy to identify in the server middleware job['args'] << { current_user_id: current_user.id } end yield end end
This runs when you call perform_async—it detects if current_user exists and tacks their ID onto the job's arguments automatically, no extra code needed when enqueuing.
Step 3: Configure Sidekiq to Use the Middlewares
Add this to your config/initializers/sidekiq.rb to register both middlewares:
Sidekiq.configure_server do |config| config.server_middleware do |chain| chain.add SidekiqServerMiddleware end end Sidekiq.configure_client do |config| config.client_middleware do |chain| chain.add SidekiqClientMiddleware end end
Step 4: Access current_user in Your Jobs
Now, in any Sidekiq job, you can grab the current user directly from the thread-local storage:
class MyWorker include Sidekiq::Worker def perform(some_arg, another_arg) user = Thread.current[:current_user] return unless user.present? # Use the user context as needed—e.g., log actions, filter data, or associate records puts "Executing job triggered by: #{user.email}" end end
You don't need to pass the user ID when enqueuing anymore—just call MyWorker.perform_async(some_arg, another_arg) from your controller, and the middleware handles the rest.
Edge Cases to Keep in Mind
- Jobs enqueued outside a request context: If you enqueue a job from a rake task or script where
current_userisn't available, the middleware won't add anything—make sure your job handlesuser.nil?gracefully. - Jobs that don't need current_user: This setup won't interfere—your job's
performmethod doesn't need to accept the extra arg explicitly, since we're appending it. - User deletion: If a user is deleted before the job runs,
User.find_bywill returnnil—add checks to handle this scenario (e.g., skip the job or log a warning).
This setup keeps your job enqueues clean and eliminates repetitive current_user passes across your app—perfect for cases where most jobs need to know the triggering user!
内容的提问来源于stack exchange,提问作者Ashish Gaur

