如何让Rails控制器中add方法通过Delayed Job延迟执行?
add Method in Rails Controller Let's break down why your current setup isn't working and walk through the fixes step by step.
The Core Issue in Your Code
Your current line add(a, b).delay is doing the opposite of what you want: it immediately runs add(a, b), then tries to call delay on whatever that method returns (which is nil since your add method is empty). Delayed Job can't delay a nil value, so nothing gets queued up.
Step 1: Fix the Delay Syntax (Quick Fix, Not Ideal Long-Term)
To actually delay the execution of the add method itself, you need to call delay on the controller instance first, then invoke the method:
def create # This tells Delayed Job to queue the `add` method with arguments a and b delay.add(a, b) end
But wait—controllers are not designed to be serialized for background jobs. Controllers hold references to request-specific objects (like params, session, or response) that can't be safely serialized and deserialized by Delayed Job. This might lead to errors or unexpected behavior down the line.
Step 2: Best Practice - Use a Dedicated Worker Class
The cleanest and most reliable way to handle background tasks in Rails (with Delayed Job) is to move your business logic into a separate worker class. Here's how:
- Create a new worker file in
app/workers/:
# app/workers/referral_add_worker.rb class ReferralAddWorker def perform(a, b) # Put your actual business logic from the `add` method here # Example: # result = a + b # ReferralRecord.create(result: result) end end
- Update your controller to enqueue this worker:
class V1::LpDeveloperReferralsController < V1::BaseController def create # Grab your a and b values from params first (assuming they come from the request) a = params[:a].to_i # Adjust type as needed b = params[:b].to_i # Queue the worker with Delayed Job ReferralAddWorker.new.delay.perform(a, b) # Or use the explicit enqueue syntax if you prefer: # Delayed::Job.enqueue ReferralAddWorker.new, args: [a, b] end end
Step 3: Verify Delayed Job Setup
Make sure your Delayed Job installation is complete and running:
- Check that
gem 'delayed_job_active_record'(or your chosen backend) is in yourGemfile, then runbundle install. - Run the migration to create the
delayed_jobstable:rails generate delayed_job:active_record rails db:migrate - Start the Delayed Job worker process (this is critical—jobs won't run unless the worker is active):
For production, use a process manager likerails jobs:worksystemdorforemanto keep the worker running continuously.
Step 4: Ensure Your Arguments Are Serializable
Delayed Job needs to serialize the arguments you pass to the background task. Avoid passing complex objects (like unsaved ActiveRecord instances, request objects, or custom classes without serialization support). Instead:
- Use simple types (strings, integers, floats).
- If you need to pass an ActiveRecord object, pass its
idand fetch it again in the worker:# Controller user_id = current_user.id ReferralAddWorker.new.delay.perform(user_id, a, b) # Worker def perform(user_id, a, b) user = User.find(user_id) # Do something with user, a, and b end
Testing It Out
After making these changes:
- Start your Rails server and send a request to the
createendpoint. - Check your
delayed_jobstable (runrails cthenDelayed::Job.all—you should see a new job entry). - Make sure the worker is running, and verify that the
performmethod in your worker executes as expected.
内容的提问来源于stack exchange,提问作者Kingsley Simon




