resque-concurrent-restriction 0.5.2 → 0.5.4
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/lib/resque/plugins/concurrent_restriction/concurrent_restriction_job.rb +26 -1
- data/lib/resque/plugins/concurrent_restriction/resque_worker_extension.rb +21 -12
- data/lib/resque/plugins/concurrent_restriction/version.rb +1 -1
- data/spec/concurrent_restriction_job_spec.rb +24 -1
- data/spec/resque_worker_extensions_spec.rb +30 -0
- metadata +43 -50
@@ -1,7 +1,32 @@
|
|
1
|
+
# To configure resque concurrent restriction, add something like the
|
2
|
+
# following to an initializer (defaults shown):
|
3
|
+
#
|
4
|
+
# Resque::Plugins::ConcurrentRestriction.configure do |config|
|
5
|
+
# # The lock timeout for the restriction queue lock
|
6
|
+
# config.lock_timeout = 60
|
7
|
+
# # Try to pick jobs off of the restricted queue before normal queues
|
8
|
+
# config.restricted_before_queued = true
|
9
|
+
# end
|
10
|
+
|
1
11
|
module Resque
|
2
12
|
module Plugins
|
3
13
|
module ConcurrentRestriction
|
4
14
|
|
15
|
+
# Allows configuring via class accessors
|
16
|
+
class << self
|
17
|
+
# optional
|
18
|
+
attr_accessor :lock_timeout, :restricted_before_queued
|
19
|
+
end
|
20
|
+
|
21
|
+
# default values
|
22
|
+
self.lock_timeout = 60
|
23
|
+
self.restricted_before_queued = false
|
24
|
+
|
25
|
+
# Allows configuring via class accessors
|
26
|
+
def self.configure
|
27
|
+
yield self
|
28
|
+
end
|
29
|
+
|
5
30
|
# Redis Data Structures
|
6
31
|
#
|
7
32
|
# concurrent.lock.tracking_id => timestamp
|
@@ -317,7 +342,7 @@ module Resque
|
|
317
342
|
exp_backoff = 1
|
318
343
|
|
319
344
|
while trying do
|
320
|
-
lock_expiration = Time.now.to_i +
|
345
|
+
lock_expiration = Time.now.to_i + ConcurrentRestriction.lock_timeout
|
321
346
|
if acquire_lock(lock_key, lock_expiration)
|
322
347
|
begin
|
323
348
|
yield
|
@@ -14,7 +14,7 @@ module Resque
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
# Wrap reserve so we can pass the job to done_working to release restriction if
|
17
|
+
# Wrap reserve so we can pass the job to done_working to release restriction if necessary
|
18
18
|
def reserve_with_restriction
|
19
19
|
@job_in_progress = reserve_without_restriction
|
20
20
|
return @job_in_progress
|
@@ -47,6 +47,26 @@ module Resque
|
|
47
47
|
# Wrap reserve so we can move a job to restriction queue if it is restricted
|
48
48
|
# This needs to be a class method
|
49
49
|
def reserve_with_restriction(queue)
|
50
|
+
order = [:get_queued_job, :get_restricted_job]
|
51
|
+
order.reverse! if ConcurrentRestriction.restricted_before_queued
|
52
|
+
|
53
|
+
resque_job = nil
|
54
|
+
order.each do |m|
|
55
|
+
resque_job ||= self.send(m, queue)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Return job or nil to move on to next queue if we couldn't get a job
|
59
|
+
return resque_job
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_restricted_job(queue)
|
63
|
+
# Try to find a runnable job from restriction queues
|
64
|
+
# This also acquires a restriction lock, which is released in done_working
|
65
|
+
resque_job = ConcurrentRestrictionJob.next_runnable_job(queue)
|
66
|
+
return resque_job
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_queued_job(queue)
|
50
70
|
resque_job = reserve_without_restriction(queue)
|
51
71
|
|
52
72
|
if resque_job
|
@@ -60,21 +80,10 @@ module Resque
|
|
60
80
|
# Move on to next if job is restricted
|
61
81
|
# If job is runnable, we keep the lock until done_working
|
62
82
|
resque_job = nil if job_class.stash_if_restricted(resque_job)
|
63
|
-
|
64
83
|
end
|
65
|
-
|
66
|
-
else
|
67
|
-
# if no queues have a runnable job, then try to find a
|
68
|
-
# runnable job from restriction queues
|
69
|
-
# This also acquires a restriction lock, which is released in done_working
|
70
|
-
resque_job = ConcurrentRestrictionJob.next_runnable_job(queue)
|
71
|
-
|
72
|
-
return resque_job
|
73
84
|
end
|
74
85
|
|
75
|
-
# Return job or nil to move on to next queue if we couldn't get a job
|
76
86
|
return resque_job
|
77
|
-
|
78
87
|
end
|
79
88
|
|
80
89
|
end
|
@@ -9,12 +9,36 @@ describe Resque::Plugins::ConcurrentRestriction do
|
|
9
9
|
|
10
10
|
after(:each) do
|
11
11
|
Resque.redis.lrange("failed", 0, -1).size.should == 0
|
12
|
+
Resque.redis.get("stat:failed").to_i.should == 0
|
12
13
|
end
|
13
14
|
|
14
15
|
it "should follow the convention" do
|
15
16
|
Resque::Plugin.lint(Resque::Plugins::ConcurrentRestrictionJob)
|
16
17
|
end
|
17
18
|
|
19
|
+
context "settings" do
|
20
|
+
|
21
|
+
it "should allow setting/getting global config for lock_timeout" do
|
22
|
+
Resque::Plugins::ConcurrentRestriction.lock_timeout.should == 60
|
23
|
+
Resque::Plugins::ConcurrentRestriction.configure do |config|
|
24
|
+
config.lock_timeout = 61
|
25
|
+
end
|
26
|
+
Resque::Plugins::ConcurrentRestriction.lock_timeout.should == 61
|
27
|
+
Resque::Plugins::ConcurrentRestriction.lock_timeout = 60
|
28
|
+
Resque::Plugins::ConcurrentRestriction.lock_timeout.should == 60
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should allow setting/getting global config for restricted_before_queued" do
|
32
|
+
Resque::Plugins::ConcurrentRestriction.restricted_before_queued.should == false
|
33
|
+
Resque::Plugins::ConcurrentRestriction.configure do |config|
|
34
|
+
config.restricted_before_queued = true
|
35
|
+
end
|
36
|
+
Resque::Plugins::ConcurrentRestriction.restricted_before_queued.should == true
|
37
|
+
Resque::Plugins::ConcurrentRestriction.restricted_before_queued = false
|
38
|
+
Resque::Plugins::ConcurrentRestriction.restricted_before_queued.should == false
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
18
42
|
|
19
43
|
context "keys" do
|
20
44
|
it "should always contain the classname in tracking_key" do
|
@@ -180,7 +204,6 @@ describe Resque::Plugins::ConcurrentRestriction do
|
|
180
204
|
ConcurrentRestrictionJob.restricted?(ConcurrentRestrictionJob.tracking_key).should == false
|
181
205
|
ConcurrentRestrictionJob.set_running_count(ConcurrentRestrictionJob.tracking_key, 1)
|
182
206
|
ConcurrentRestrictionJob.restricted?(ConcurrentRestrictionJob.tracking_key).should == true
|
183
|
-
|
184
207
|
end
|
185
208
|
|
186
209
|
end
|
@@ -9,6 +9,7 @@ describe Resque::Plugins::ConcurrentRestriction::Worker do
|
|
9
9
|
|
10
10
|
after(:each) do
|
11
11
|
Resque.redis.lrange("failed", 0, -1).size.should == 0
|
12
|
+
Resque.redis.get("stat:failed").to_i.should == 0
|
12
13
|
end
|
13
14
|
|
14
15
|
it "should do nothing for no jobs" do
|
@@ -58,6 +59,8 @@ describe Resque::Plugins::ConcurrentRestriction::Worker do
|
|
58
59
|
end
|
59
60
|
|
60
61
|
it "should prefer running a normal job over one on restriction queue" do
|
62
|
+
Resque::Plugins::ConcurrentRestriction.restricted_before_queued.should == false
|
63
|
+
|
61
64
|
RestrictionJob.set_running_count(RestrictionJob.tracking_key, 99)
|
62
65
|
|
63
66
|
run_resque_job(RestrictionJob, :queue => :normal)
|
@@ -74,6 +77,32 @@ describe Resque::Plugins::ConcurrentRestriction::Worker do
|
|
74
77
|
RestrictionJob.restriction_queue(RestrictionJob.tracking_key, :normal).should == []
|
75
78
|
NoRestrictionJob.run_count.should == 1
|
76
79
|
RestrictionJob.run_count.should == 1
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should prefer running a restricted job over normal one when option given" do
|
84
|
+
begin
|
85
|
+
Resque::Plugins::ConcurrentRestriction.restricted_before_queued = true
|
86
|
+
|
87
|
+
RestrictionJob.set_running_count(RestrictionJob.tracking_key, 99)
|
88
|
+
|
89
|
+
run_resque_job(RestrictionJob, :queue => :normal)
|
90
|
+
RestrictionJob.run_count.should == 0
|
91
|
+
|
92
|
+
RestrictionJob.set_running_count(RestrictionJob.tracking_key, 0)
|
93
|
+
|
94
|
+
run_resque_job(NoRestrictionJob, :queue => :normal)
|
95
|
+
RestrictionJob.restriction_queue(RestrictionJob.tracking_key, :normal).should == []
|
96
|
+
NoRestrictionJob.run_count.should == 0
|
97
|
+
RestrictionJob.run_count.should == 1
|
98
|
+
|
99
|
+
run_resque_queue(:normal)
|
100
|
+
RestrictionJob.restriction_queue(RestrictionJob.tracking_key, :normal).should == []
|
101
|
+
NoRestrictionJob.run_count.should == 1
|
102
|
+
RestrictionJob.run_count.should == 1
|
103
|
+
ensure
|
104
|
+
Resque::Plugins::ConcurrentRestriction.restricted_before_queued = false
|
105
|
+
end
|
77
106
|
end
|
78
107
|
|
79
108
|
it "should be able to run multiple restricted jobs in a row without exceeding restriction" do
|
@@ -154,6 +183,7 @@ describe Resque::Plugins::ConcurrentRestriction::Worker do
|
|
154
183
|
Resque.redis.lrange("failed", 0, -1).size.should == 1
|
155
184
|
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should == 0
|
156
185
|
Resque.redis.del("failed")
|
186
|
+
Resque.redis.del("stat:failed")
|
157
187
|
end
|
158
188
|
|
159
189
|
it "should handle jobs with custom restriction identifier" do
|
metadata
CHANGED
@@ -1,61 +1,57 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-concurrent-restriction
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.4
|
4
5
|
prerelease:
|
5
|
-
version: 0.5.2
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Matt Conway
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
date: 2011-04-11 00:00:00 -04:00
|
12
|
+
date: 2011-08-26 00:00:00.000000000 -04:00
|
14
13
|
default_executable:
|
15
|
-
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
17
16
|
name: resque
|
18
|
-
|
19
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
17
|
+
requirement: &2168987840 !ruby/object:Gem::Requirement
|
20
18
|
none: false
|
21
|
-
requirements:
|
19
|
+
requirements:
|
22
20
|
- - ~>
|
23
|
-
- !ruby/object:Gem::Version
|
24
|
-
version:
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '1.10'
|
25
23
|
type: :runtime
|
26
|
-
version_requirements: *id001
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rspec
|
29
24
|
prerelease: false
|
30
|
-
|
25
|
+
version_requirements: *2168987840
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rspec
|
28
|
+
requirement: &2168987340 !ruby/object:Gem::Requirement
|
31
29
|
none: false
|
32
|
-
requirements:
|
30
|
+
requirements:
|
33
31
|
- - ~>
|
34
|
-
- !ruby/object:Gem::Version
|
35
|
-
version:
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.5'
|
36
34
|
type: :development
|
37
|
-
version_requirements: *id002
|
38
|
-
- !ruby/object:Gem::Dependency
|
39
|
-
name: awesome_print
|
40
35
|
prerelease: false
|
41
|
-
|
36
|
+
version_requirements: *2168987340
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: awesome_print
|
39
|
+
requirement: &2168986960 !ruby/object:Gem::Requirement
|
42
40
|
none: false
|
43
|
-
requirements:
|
44
|
-
- -
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version:
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
47
45
|
type: :development
|
48
|
-
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *2168986960
|
49
48
|
description: A resque plugin for limiting how many of a specific job can run concurrently
|
50
|
-
email:
|
49
|
+
email:
|
51
50
|
- matt@conwaysplace.com
|
52
51
|
executables: []
|
53
|
-
|
54
52
|
extensions: []
|
55
|
-
|
56
53
|
extra_rdoc_files: []
|
57
|
-
|
58
|
-
files:
|
54
|
+
files:
|
59
55
|
- .gitignore
|
60
56
|
- Gemfile
|
61
57
|
- LICENSE
|
@@ -74,32 +70,29 @@ files:
|
|
74
70
|
has_rdoc: true
|
75
71
|
homepage: http://github.com/wr0ngway/resque-concurrent-restriction
|
76
72
|
licenses: []
|
77
|
-
|
78
73
|
post_install_message:
|
79
74
|
rdoc_options: []
|
80
|
-
|
81
|
-
require_paths:
|
75
|
+
require_paths:
|
82
76
|
- lib
|
83
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
78
|
none: false
|
85
|
-
requirements:
|
86
|
-
- -
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version:
|
89
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
84
|
none: false
|
91
|
-
requirements:
|
92
|
-
- -
|
93
|
-
- !ruby/object:Gem::Version
|
94
|
-
version:
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
95
89
|
requirements: []
|
96
|
-
|
97
90
|
rubyforge_project: resque-concurrent-restriction
|
98
|
-
rubygems_version: 1.6.
|
91
|
+
rubygems_version: 1.6.2
|
99
92
|
signing_key:
|
100
93
|
specification_version: 3
|
101
94
|
summary: A resque plugin for limiting how many of a specific job can run concurrently
|
102
|
-
test_files:
|
95
|
+
test_files:
|
103
96
|
- spec/concurrent_restriction_job_spec.rb
|
104
97
|
- spec/redis-test.conf
|
105
98
|
- spec/resque_worker_extensions_spec.rb
|