diff --git a/lib/resque/plugins/retry.rb b/lib/resque/plugins/retry.rb index 61946dc..056f786 100644 --- a/lib/resque/plugins/retry.rb +++ b/lib/resque/plugins/retry.rb @@ -410,9 +410,13 @@ def after_perform_retry(*args) # @api private def on_failure_retry(exception, *args) log_message 'on_failure_retry', args, exception - if @on_failure_retry_hook_already_called + if exception.is_a?(Resque::DirtyExit) + # This hook is called from a worker processes, not the job process + # that failed with a DirtyExit, so @retry_attempt wasn't set yet + @retry_attempt = Resque.redis.get(redis_retry_key(*args)).to_i + elsif @on_failure_retry_hook_already_called log_message 'on_failure_retry_hook_already_called', args, exception - return + return end if retry_criteria_valid?(exception, *args) diff --git a/test/retry_test.rb b/test/retry_test.rb index e7c5bb1..70277ad 100644 --- a/test/retry_test.rb +++ b/test/retry_test.rb @@ -312,4 +312,22 @@ def test_expire_key_setting_on_the_fly perform_next_job(@worker) end end + + if Process.respond_to?(:fork) && Gem::Version.new(Resque::VERSION) >= Gem::Version.new('1.20.0') + def test_retry_on_dirty_exit + Resque.enqueue(RetryKilledJob) + RetryKilledJob.expects(:clean_retry_key).once + 2.times do + job = @worker.reserve + child = fork do + Resque.redis.client.reconnect + job.perform + end + Process.waitpid(child) + job.fail(Resque::DirtyExit.new) + end + + assert_equal nil, @worker.reserve + end + end end diff --git a/test/test_jobs.rb b/test/test_jobs.rb index 921af3a..daf1f69 100644 --- a/test/test_jobs.rb +++ b/test/test_jobs.rb @@ -503,3 +503,12 @@ class FailsDuringConnectJob < RetryDefaultsJob @retry_limit = 3 @retry_delay = 10 end + +class RetryKilledJob + extend Resque::Plugins::Retry + @queue = :testing + + def self.perform(*args) + Process.kill("KILL", Process.pid) + end +end