Permalink
Browse files

resque-workers-lock

  • Loading branch information...
1 parent 574671a commit 81ac45a43b823022a3018914a4de7187ed03b4e1 @bartolsthoorn committed Jul 23, 2012
Showing with 183 additions and 2 deletions.
  1. +8 −0 Gemfile
  2. +22 −0 LICENSE
  3. +28 −2 README.md
  4. +24 −0 Rakefile
  5. +32 −0 lib/resque/plugins/workers/lock.rb
  6. +29 −0 resque-workers-lock.gemspec
  7. +40 −0 test/lock_test.rb
View
@@ -0,0 +1,8 @@
+source :rubygems
+
+gem "resque"
+
+group :development do
+ gem "turn"
+ gem "rake"
+end
View
22 LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2012 Bart Olsthoorn, website: bartolsthoorn.nl
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
View
@@ -1,2 +1,28 @@
-resque-workers-lock
-===================
+# Resque Workers Lock
+This is a [resque](https://github.com/defunkt/resque) plugin inspired by [resque-lock](https://github.com/defunkt/resque-lock) and requires Resque 1.7.0.
+
+## What does it do?
+If resque jobs have the same lock applied this means that those jobs cannot be processed simultaneously by two or more workers.
+
+## The Lock
+By default the lock is the instance name + arguments. Override this lock to lock on specific arguments.
+
+## How does it differ from resque-lock
+Resque-lock will not let you queue jobs when you locked them. Resque-workers-lock locks on a workers-level and will requeue the locked jobs.
+
+## Example
+``` ruby
+require 'resque/plugins/workers/lock'
+
+class UpdateNetworkGraph
+ extend Resque::Plugins::Workers::Lock
+
+ def self.lock(domain)
+ return domain
+ end
+
+ def self.perform(domain)
+ # do the work
+ end
+end
+```
View
@@ -0,0 +1,24 @@
+require 'rake/testtask'
+require 'rdoc/task'
+
+def command?(command)
+ system("type #{command} > /dev/null")
+end
+
+# Tests
+
+task :default => :test
+
+if command? :turn
+ desc "Run tests"
+ task :test do
+ suffix = "-n #{ENV['TEST']}" if ENV['TEST']
+ sh "turn test/*.rb #{suffix}"
+ end
+else
+ Rake::TestTask.new do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = false
+ end
+end
@@ -0,0 +1,32 @@
+module Resque
+ module Plugins
+ module Workers
+ module Lock
+ # Override in your job to control the lock key.
+ def lock(*args)
+ "lock:#{name}-#{args.to_s}"
+ end
+
+ def before_perform_with_lock(*args)
+ nx = Resque.redis.setnx(lock(*args), true)
+ raise Resque::Failure, "worker locked" unless nx
+ end
+
+ def on_failure_retry(e, *args)
+ Logger.info "Performing #{self} caused an exception (#{e}). Retrying..."
+ Resque.enqueue self, *args
+ end
+
+ def around_perform_lock(*args)
+ begin
+ yield
+ ensure
+ # Always clear the lock when we're done, even if there is an
+ # error.
+ Resque.redis.del(lock(*args))
+ end
+ end
+ end
+ end
+ end
+end
@@ -0,0 +1,29 @@
+Gem::Specification.new do |s|
+ s.name = "resque-workers-lock"
+ s.version = "1.0.0"
+ s.date = Time.now.strftime('%Y-%m-%d')
+ s.summary = "Resque plugin, prevent specific jobs to be processed simultaneously by multiple workers."
+ s.homepage = "http://github.com/defunkt/resque-lock"
+ s.email = "bartolsthoorn@gmail.com"
+ s.authors = [ "Bart Olsthoorn" ]
+ s.has_rdoc = false
+
+ s.files = %w( README.md Rakefile LICENSE )
+ s.files += Dir.glob("lib/**/*")
+ s.files += Dir.glob("test/**/*")
+
+ s.description = <<desc
+A Resque plugin. If you want to prevent specific jobs to be processed simultaneously,
+extend it with this module. It locks on the first argument in the perform method.
+
+For example:
+
+ class UpdateNetworkGraph
+ extend Resque::Workers::Lock
+
+ def self.perform(domain)
+ # Do HTTP request to domain
+ end
+ end
+desc
+end
View
@@ -0,0 +1,40 @@
+require 'test/unit'
+require 'resque'
+require 'resque/plugins/workers/lock'
+
+$counter = 0
+
+class LockTest < Test::Unit::TestCase
+ class Job
+ extend Resque::Plugins::Workers::Lock
+ @queue = :lock_test
+
+ def self.perform
+ raise "This should not have not happened"
+ end
+ end
+
+ def setup
+ Resque.redis.del('queue:lock_test')
+ Resque.redis.del(Job.lock)
+ end
+
+ def test_lint
+ assert_nothing_raised do
+ Resque::Plugin.lint(Resque::Plugins::Workers::Lock)
+ end
+ end
+
+ def test_version
+ major, minor, patch = Resque::Version.split('.')
+ assert_equal 1, major.to_i
+ assert minor.to_i >= 17
+ assert Resque::Plugin.respond_to?(:before_enqueue_hooks)
+ end
+
+ def test_lock
+ 3.times { Resque.enqueue(Job) }
+
+ assert_equal 3, Resque.redis.llen('queue:lock_test')
+ end
+end

0 comments on commit 81ac45a

Please sign in to comment.