-
Notifications
You must be signed in to change notification settings - Fork 478
Description
Description
When resque-scheduler fires a recurring/cron job via enqueue_recurring, it calls before_delayed_enqueue even though the job was never in the delayed queue. This hook should only be called when a job is being moved from the delayed queue to the work queue.
Expected Behavior
before_delayed_enqueueshould only be called when a job is being transferred from the delayed queue to the regular queue- Recurring/cron jobs never enter the delayed queue, so this hook should not fire for them
Actual Behavior
When a cron job fires:
enqueue_recurringcallsenqueue(config)which callsenqueue_from_configenqueue_from_configcallsrun_before_delayed_enqueue_hooksunconditionally- The hook fires even though the job was never delayed
Root Cause
In scheduler.rb, enqueue_from_config (line ~335) calls before_delayed_enqueue unconditionally:
Reproduction Script
#!/usr/bin/env ruby
#
# Demonstrates bug: before_delayed_enqueue fires for cron jobs that never touched the delayed queue.
#
# Prerequisites: Redis running on localhost:6379
# Run with: ruby <filename.rb>
require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "resque", "~> 2.6"
gem "resque-scheduler", "~> 4.11"
end
require "resque"
require "resque-scheduler"
redis = Redis.new(db: 15)
Resque.redis = redis
redis.flushdb
class CronTestJob
@queue = :default
@hook_call_count = 0
class << self
attr_accessor :hook_call_count
end
def self.perform(*args)
puts "Job performed"
end
def self.before_delayed_enqueue_track(*args)
@hook_call_count += 1
puts "HOOK: before_delayed_enqueue_track called (count: #{@hook_call_count})"
end
end
puts "=== Simulating a CRON job firing ==="
puts ""
# Simulate what happens when rufus-scheduler triggers a cron job
cron_config = {
"class" => "CronTestJob",
"args" => ["cron_arg"],
"queue" => "default"
}
# This is what enqueue_recurring eventually calls
Resque::Scheduler.enqueue_from_config(cron_config)
puts ""
puts "=== Summary ==="
puts "before_delayed_enqueue hook calls: #{CronTestJob.hook_call_count} (expected: 0)"
puts ""
if CronTestJob.hook_call_count > 0
puts "BUG CONFIRMED: before_delayed_enqueue should be 0 for cron jobs!"
else
puts "OK: Hook behavior is correct"
end
redis.flushdb
Output:
=== Simulating a CRON job firing ===
HOOK: before_delayed_enqueue_track called (count: 1)
=== Summary ===
before_delayed_enqueue hook calls: 1 (expected: 0)
BUG CONFIRMED: before_delayed_enqueue should be 0 for cron jobs!
Suggested Fix
This is obviously related to #810. And it also tackles the same question we had there and in #812. I think it is still not easy to answer, whether the before/after_schedule hooks should also fire for recurring jobs, as they never touch the delayed queue.
After also discovering this I actually want to propose to introduce a new hook type: before/after_recurring. With #812 as a base this would not be complicated and we could have dedicated hooks for adding jobs to and moving them from the delayed queue (the existing before/after_schedule) and before/after_recurring just for recurring operations, that are a schedule but no delay.