Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #398 from humancopy/resque

---

Before & after hooks for dequeue.

Needed this to resolve deadlocks with resque-lock when dequeuing a job (see: humancopy/resque-lock@740f1ab).

Thanks. ;)
  • Loading branch information...
commit c8a3e0a1e6ecf6632c30088802d9ec1a02045b13 2 parents 461351c + 17ad7f8
Chris Wanstrath defunkt authored
6 docs/HOOKS.md
View
@@ -72,6 +72,12 @@ The available hooks are:
* `after_enqueue`: Called with the job args after a job is placed on the queue.
Any exception raised propagates up to the code which queued the job.
+* `before_dequeue`: Called with the job args before a job is removed from the queue.
+ If the hook returns `false`, the job will not be removed from the queue.
+
+* `after_dequeue`: Called with the job args after a job was removed from the queue.
+ Any exception raised propagates up to the code which dequeued the job.
+
* `before_perform`: Called with the job args before perform. If it raises
`Resque::Job::DontPerform`, the job is aborted. If other exceptions
are raised, they will be propagated up the the `Resque::Failure`
10 lib/resque.rb
View
@@ -283,7 +283,17 @@ def enqueue_to(queue, klass, *args)
#
# This method is considered part of the `stable` API.
def dequeue(klass, *args)
+ # Perform before_dequeue hooks. Don't perform dequeue if any hook returns false
+ before_hooks = Plugin.before_dequeue_hooks(klass).collect do |hook|
+ klass.send(hook, *args)
+ end
+ return if before_hooks.any? { |result| result == false }
+
Job.destroy(queue_from_class(klass), klass, *args)
+
+ Plugin.after_dequeue_hooks(klass).each do |hook|
+ klass.send(hook, *args)
+ end
end
# Given a class, try to extrapolate an appropriate queue based on a
10 lib/resque/plugin.rb
View
@@ -52,5 +52,15 @@ def after_enqueue_hooks(job)
def before_enqueue_hooks(job)
job.methods.grep(/^before_enqueue/).sort
end
+
+ # Given an object, returns a list `after_dequeue` hook names.
+ def after_dequeue_hooks(job)
+ job.methods.grep(/^after_dequeue/).sort
+ end
+
+ # Given an object, returns a list `before_dequeue` hook names.
+ def before_dequeue_hooks(job)
+ job.methods.grep(/^before_dequeue/).sort
+ end
end
end
60 test/job_hooks_test.rb
View
@@ -290,6 +290,66 @@ def self.perform(history)
end
end
+context "Resque::Job after_dequeue" do
+ include PerformJob
+
+ class ::AfterDequeueJob
+ @queue = :jobs
+ def self.after_dequeue_record_history(history)
+ history << :after_dequeue
+ end
+
+ def self.perform(history)
+ end
+ end
+
+ test "the after dequeue hook should run" do
+ history = []
+ @worker = Resque::Worker.new(:jobs)
+ Resque.dequeue(AfterDequeueJob, history)
+ @worker.work(0)
+ assert_equal history, [:after_dequeue], "after_dequeue was not run"
+ end
+end
+
+
+context "Resque::Job before_dequeue" do
+ include PerformJob
+
+ class ::BeforeDequeueJob
+ @queue = :jobs
+ def self.before_dequeue_record_history(history)
+ history << :before_dequeue
+ end
+
+ def self.perform(history)
+ end
+ end
+
+ class ::BeforeDequeueJobAbort
+ @queue = :jobs
+ def self.before_dequeue_abort(history)
+ false
+ end
+
+ def self.perform(history)
+ end
+ end
+
+ test "the before dequeue hook should run" do
+ history = []
+ @worker = Resque::Worker.new(:jobs)
+ Resque.dequeue(BeforeDequeueJob, history)
+ @worker.work(0)
+ assert_equal history, [:before_dequeue], "before_dequeue was not run"
+ end
+
+ test "a before dequeue hook that returns false should prevent the job from getting dequeued" do
+ history = []
+ assert_equal nil, Resque.dequeue(BeforeDequeueJobAbort, history)
+ end
+end
+
context "Resque::Job all hooks" do
include PerformJob
Please sign in to comment.
Something went wrong with that request. Please try again.