resque-lock 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.md +51 -0
- data/Rakefile +49 -0
- data/lib/resque/plugins/lock.rb +71 -0
- data/test/lock_test.rb +34 -0
- metadata +72 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Chris Wanstrath
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
Software), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
Resque Lock
|
2
|
+
===========
|
3
|
+
|
4
|
+
A [Resque][rq] plugin. If you want only one instance of your job
|
5
|
+
running at a time, extend it with this module.
|
6
|
+
|
7
|
+
For example:
|
8
|
+
|
9
|
+
require 'resque/plugins/lock'
|
10
|
+
|
11
|
+
class UpdateNetworkGraph
|
12
|
+
extend Resque::Plugins::Lock
|
13
|
+
|
14
|
+
def self.perform(repo_id)
|
15
|
+
heavy_lifting
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
While other UpdateNetworkGraph jobs will be placed on the queue,
|
20
|
+
the Locked class will check Redis to see if any others are
|
21
|
+
executing with the same arguments before beginning. If another
|
22
|
+
is executing the job will be aborted.
|
23
|
+
|
24
|
+
If you want to define the key yourself you can override the
|
25
|
+
`lock` class method in your subclass, e.g.
|
26
|
+
|
27
|
+
class UpdateNetworkGraph
|
28
|
+
extend Resque::Plugins::Lock
|
29
|
+
|
30
|
+
Run only one at a time, regardless of repo_id.
|
31
|
+
def self.lock(repo_id)
|
32
|
+
"network-graph"
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.perform(repo_id)
|
36
|
+
heavy_lifting
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
The above modification will ensure only one job of class
|
41
|
+
UpdateNetworkGraph is running at a time, regardless of the
|
42
|
+
repo_id. Normally a job is locked using a combination of its
|
43
|
+
class name and arguments.
|
44
|
+
|
45
|
+
|
46
|
+
Dependencies
|
47
|
+
------------
|
48
|
+
|
49
|
+
* Resque 1.7.0
|
50
|
+
|
51
|
+
[rq]: http://github.com/defunkt/resque
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
|
4
|
+
def command?(command)
|
5
|
+
system("type #{command} > /dev/null")
|
6
|
+
end
|
7
|
+
|
8
|
+
#
|
9
|
+
# Tests
|
10
|
+
#
|
11
|
+
|
12
|
+
task :default => :test
|
13
|
+
|
14
|
+
if command? :turn
|
15
|
+
desc "Run tests"
|
16
|
+
task :test do
|
17
|
+
suffix = "-n #{ENV['TEST']}" if ENV['TEST']
|
18
|
+
sh "turn test/*.rb #{suffix}"
|
19
|
+
end
|
20
|
+
else
|
21
|
+
Rake::TestTask.new do |t|
|
22
|
+
t.libs << 'lib'
|
23
|
+
t.pattern = 'test/**/*_test.rb'
|
24
|
+
t.verbose = false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Gems
|
30
|
+
#
|
31
|
+
|
32
|
+
begin
|
33
|
+
require 'mg'
|
34
|
+
MG.new("resque-lock.gemspec")
|
35
|
+
|
36
|
+
desc "Build a gem."
|
37
|
+
task :gem => :package
|
38
|
+
|
39
|
+
# Ensure tests pass before pushing a gem.
|
40
|
+
task :gemcutter => :test
|
41
|
+
|
42
|
+
desc "Push a new version to Gemcutter and publish docs."
|
43
|
+
task :publish => :gemcutter do
|
44
|
+
sh "git push origin master --tags"
|
45
|
+
end
|
46
|
+
rescue LoadError
|
47
|
+
warn "mg not available."
|
48
|
+
warn "Install it with: gem i mg"
|
49
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Resque
|
2
|
+
module Plugins
|
3
|
+
# If you want only one instance of your job running at a time,
|
4
|
+
# extend it with this module.
|
5
|
+
#
|
6
|
+
# For example:
|
7
|
+
#
|
8
|
+
# require 'resque/plugins/lock'
|
9
|
+
#
|
10
|
+
# class UpdateNetworkGraph
|
11
|
+
# extend Resque::Plugins::Lock
|
12
|
+
#
|
13
|
+
# def self.perform(repo_id)
|
14
|
+
# heavy_lifting
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# While other UpdateNetworkGraph jobs will be placed on the queue,
|
19
|
+
# the Lock class will check Redis to see if any others are
|
20
|
+
# executing with the same arguments before beginning. If another
|
21
|
+
# is executing the job will be aborted.
|
22
|
+
#
|
23
|
+
# If you want to define the key yourself you can override the
|
24
|
+
# `lock` class method in your subclass, e.g.
|
25
|
+
#
|
26
|
+
# class UpdateNetworkGraph
|
27
|
+
# extend Resque::Plugins::Lock
|
28
|
+
#
|
29
|
+
# # Run only one at a time, regardless of repo_id.
|
30
|
+
# def self.lock(repo_id)
|
31
|
+
# "network-graph"
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# def self.perform(repo_id)
|
35
|
+
# heavy_lifting
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# The above modification will ensure only one job of class
|
40
|
+
# UpdateNetworkGraph is running at a time, regardless of the
|
41
|
+
# repo_id. Normally a job is locked using a combination of its
|
42
|
+
# class name and arguments.
|
43
|
+
module Lock
|
44
|
+
# Override in your job to control the lock key. It is
|
45
|
+
# passed the same arguments as `perform`, that is, your job's
|
46
|
+
# payload.
|
47
|
+
def lock(*args)
|
48
|
+
"lock:#{name}-#{args.to_s}"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Convenience method, not used internally.
|
52
|
+
def locked?
|
53
|
+
Resque.redis.exist(lock)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Where the magic happens.
|
57
|
+
def around_perform_lock(*args)
|
58
|
+
# Abort if another job has created a lock.
|
59
|
+
return unless Resque.redis.setnx(lock(*args), true)
|
60
|
+
|
61
|
+
begin
|
62
|
+
yield
|
63
|
+
ensure
|
64
|
+
# Always clear the lock when we're done, even if there is an
|
65
|
+
# error.
|
66
|
+
Resque.redis.del(lock(*args))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/test/lock_test.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'resque'
|
3
|
+
require 'resque/plugins/lock'
|
4
|
+
|
5
|
+
$counter = 0
|
6
|
+
|
7
|
+
class Job
|
8
|
+
extend Resque::Plugins::Lock
|
9
|
+
@queue = :test
|
10
|
+
|
11
|
+
def self.perform
|
12
|
+
$counter += 1
|
13
|
+
sleep 1
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class LockTest < Test::Unit::TestCase
|
18
|
+
def test_version
|
19
|
+
assert_equal '1.7.0', Resque::Version
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_lock
|
23
|
+
3.times { Resque.enqueue(Job) }
|
24
|
+
worker = Resque::Worker.new(:test)
|
25
|
+
|
26
|
+
workers = []
|
27
|
+
3.times do
|
28
|
+
workers << Thread.new { worker.process }
|
29
|
+
end
|
30
|
+
workers.each { |t| t.join }
|
31
|
+
|
32
|
+
assert_equal 1, $counter
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: resque-lock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Wanstrath
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-04-01 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: |
|
17
|
+
A Resque plugin. If you want only one instance of your job
|
18
|
+
running at a time, extend it with this module.
|
19
|
+
|
20
|
+
For example:
|
21
|
+
|
22
|
+
class UpdateNetworkGraph
|
23
|
+
extend Resque::Jobs::Locked
|
24
|
+
|
25
|
+
def self.perform(repo_id)
|
26
|
+
heavy_lifting
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
email: chris@ozmm.org
|
31
|
+
executables: []
|
32
|
+
|
33
|
+
extensions: []
|
34
|
+
|
35
|
+
extra_rdoc_files: []
|
36
|
+
|
37
|
+
files:
|
38
|
+
- README.md
|
39
|
+
- Rakefile
|
40
|
+
- LICENSE
|
41
|
+
- lib/resque/plugins/lock.rb
|
42
|
+
- test/lock_test.rb
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/defunkt/resque-lock
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.3.5
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: A Resque plugin for ensuring only one instance of your job is running at a time.
|
71
|
+
test_files: []
|
72
|
+
|