Rails中Delayed Job执行两次问题排查与修复求助
Hey there! Let's break down why your SimpleJob is running twice and how to fix it. Based on your setup, here are the most likely causes and solutions:
1. Initializer Script Gets Loaded Multiple Times
You mentioned adding SimpleJob.schedule! in config/initializers/job_initializers.rb. Rails can re-run initializers in certain scenarios—like code reloading in development mode, or when using a server that spins up multiple worker processes (Puma/Unicorn). Each reload/process launch triggers the initializer again, scheduling the job twice.
Fix:
Add a guard clause to ensure the job is only scheduled once:
# config/initializers/job_initializers.rb # Option 1: Check if the job already exists in Delayed Job unless Delayed::Job.exists?(handler: /SimpleJob/) SimpleJob.schedule! end # Option 2: Use a global flag to prevent repeats unless defined?($simple_job_already_scheduled) $simple_job_already_scheduled = true SimpleJob.schedule! end
2. Multiple Server Workers Trigger Scheduling
If your app server runs multiple worker processes (common in production or even development with Puma's default settings), each process will execute the initializer independently—resulting in duplicate job schedules.
Fix:
Move the scheduling logic out of initializers and into a one-time rake task. Create lib/tasks/schedule_jobs.rake:
namespace :jobs do desc "Schedule one-time recurring jobs" task schedule: :environment do SimpleJob.schedule! end end
Run it manually after starting your server: rails jobs:schedule, or add it to your deployment script (like Capistrano) to run once per deploy.
3. Delayed Job's Retry Mechanism Is Triggering
If your job hits a temporary error (e.g., a brief database connection blip) during execution, Delayed Job defaults to retrying the task. If the error resolves quickly, you'll see two execution logs and two database records.
Fix:
Check your logs for retry messages, then adjust the job's retry policy:
class SimpleJob < ApplicationJob queue_as :default # Disable retries entirely if you don't need them retry_on StandardError, attempts: 0 # Or set longer wait times to avoid immediate repeats # retry_on StandardError, wait: 5.minutes, attempts: 3 def perform # Your job logic here end end
4. Flawed Scheduling Logic in schedule!
If your SimpleJob.schedule! method doesn't check for existing pending jobs, every call will create a new task—leading to duplicates.
Fix:
Update the schedule! method to only create a job if none are pending:
class SimpleJob < ApplicationJob def self.schedule! # Skip if there's already a pending SimpleJob unless Delayed::Job.where(handler: /SimpleJob/).exists? set(wait: 1.minute).perform_later # Adjust wait time as needed end end end
5. Development Mode Code Reloading
In development, Rails auto-reloads classes when you modify code, which can re-run initializers and re-schedule the job.
Fix:
Avoid scheduling jobs via initializers in development. Instead, run SimpleJob.schedule! manually in the Rails console when you need it, or use the rake task mentioned earlier.
内容的提问来源于stack exchange,提问作者onder

