resque-concurrent-restriction 0.5.4 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +10 -0
- data/lib/resque/plugins/concurrent_restriction/concurrent_restriction_job.rb +9 -5
- data/lib/resque/plugins/concurrent_restriction/version.rb +1 -1
- data/resque-concurrent-restriction.gemspec +5 -0
- data/spec/concurrent_restriction_job_spec.rb +13 -6
- data/spec/redis-test.conf +1 -1
- data/spec/resque_worker_extensions_spec.rb +46 -9
- data/spec/spec_helper.rb +35 -16
- metadata +58 -11
data/.travis.yml
ADDED
@@ -130,7 +130,7 @@ module Resque
|
|
130
130
|
"concurrent.runnable#{key}"
|
131
131
|
end
|
132
132
|
|
133
|
-
# Encodes the job
|
133
|
+
# Encodes the job into the restriction queue
|
134
134
|
def encode(job)
|
135
135
|
item = {:queue => job.queue, :payload => job.payload}
|
136
136
|
Resque.encode(item)
|
@@ -189,7 +189,6 @@ module Resque
|
|
189
189
|
decrement_queue_count(queue)
|
190
190
|
|
191
191
|
# increment by one to indicate that we are running
|
192
|
-
# do this before update_queues_available so that the current queue gets cleaned
|
193
192
|
increment_running_count(tracking_key) if str
|
194
193
|
|
195
194
|
decode(str)
|
@@ -226,10 +225,15 @@ module Resque
|
|
226
225
|
return restricted
|
227
226
|
end
|
228
227
|
|
228
|
+
# The value in redis is the number of jobs currently running
|
229
|
+
# If we increment past that, we are restricted. Incrementing is only done
|
230
|
+
# after the job is cleared for execution due to checking the runnable
|
231
|
+
# state, and post increment we setup runnable for future jobs based on
|
232
|
+
# the new "restricted" value
|
229
233
|
def increment_running_count(tracking_key)
|
230
234
|
count_key = running_count_key(tracking_key)
|
231
235
|
value = Resque.redis.incr(count_key)
|
232
|
-
restricted = (value
|
236
|
+
restricted = (value >= concurrent_limit)
|
233
237
|
mark_runnable(tracking_key, !restricted)
|
234
238
|
return restricted
|
235
239
|
end
|
@@ -351,7 +355,7 @@ module Resque
|
|
351
355
|
end
|
352
356
|
trying = false
|
353
357
|
else
|
354
|
-
sleep
|
358
|
+
sleep(rand(1000) * 0.0001 * exp_backoff)
|
355
359
|
exp_backoff *= 2
|
356
360
|
end
|
357
361
|
end
|
@@ -391,7 +395,7 @@ module Resque
|
|
391
395
|
lock_key = lock_key(tracking_key)
|
392
396
|
|
393
397
|
run_atomically(lock_key) do
|
394
|
-
|
398
|
+
|
395
399
|
# since we don't have a lock when we get the runnable,
|
396
400
|
# we need to check it again
|
397
401
|
still_runnable = runnable?(tracking_key, queue)
|
@@ -21,7 +21,12 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.require_paths = ["lib"]
|
22
22
|
|
23
23
|
s.add_dependency("resque", '~> 1.10')
|
24
|
+
|
25
|
+
s.add_development_dependency('json')
|
24
26
|
s.add_development_dependency('rspec', '~> 2.5')
|
25
27
|
s.add_development_dependency('awesome_print')
|
26
28
|
|
29
|
+
# Needed for testing newer resque on ruby 1.8.7
|
30
|
+
s.add_development_dependency('json')
|
31
|
+
|
27
32
|
end
|
@@ -61,7 +61,7 @@ describe Resque::Plugins::ConcurrentRestriction do
|
|
61
61
|
|
62
62
|
it "should encode jobs correctly" do
|
63
63
|
job = Resque::Job.new("somequeue", {"class" => "RestrictionJob", "args" => [1, 2, 3]})
|
64
|
-
ConcurrentRestrictionJob.encode(job).should == '{"queue":"somequeue","payload":{"class":"RestrictionJob","args":[1,2,3]}}'
|
64
|
+
JSON.parse(ConcurrentRestrictionJob.encode(job)).should == JSON.parse('{"queue":"somequeue","payload":{"class":"RestrictionJob","args":[1,2,3]}}')
|
65
65
|
end
|
66
66
|
|
67
67
|
it "should decode jobs correctly" do
|
@@ -177,23 +177,30 @@ describe Resque::Plugins::ConcurrentRestriction do
|
|
177
177
|
end
|
178
178
|
|
179
179
|
it "should increment running count" do
|
180
|
-
ConcurrentRestrictionJob.stub!(:concurrent_limit).and_return(
|
180
|
+
ConcurrentRestrictionJob.stub!(:concurrent_limit).and_return(2)
|
181
181
|
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should == 0
|
182
182
|
ConcurrentRestrictionJob.increment_running_count(ConcurrentRestrictionJob.tracking_key).should == false
|
183
183
|
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should == 1
|
184
184
|
ConcurrentRestrictionJob.increment_running_count(ConcurrentRestrictionJob.tracking_key).should == true
|
185
185
|
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should == 2
|
186
|
+
ConcurrentRestrictionJob.increment_running_count(ConcurrentRestrictionJob.tracking_key).should == true
|
187
|
+
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should == 3
|
186
188
|
end
|
187
189
|
|
188
190
|
it "should decrement running count" do
|
189
|
-
ConcurrentRestrictionJob.stub!(:concurrent_limit).and_return(
|
190
|
-
ConcurrentRestrictionJob.set_running_count(ConcurrentRestrictionJob.tracking_key,
|
191
|
+
ConcurrentRestrictionJob.stub!(:concurrent_limit).and_return(2)
|
192
|
+
ConcurrentRestrictionJob.set_running_count(ConcurrentRestrictionJob.tracking_key, 3)
|
191
193
|
ConcurrentRestrictionJob.decrement_running_count(ConcurrentRestrictionJob.tracking_key).should == true
|
192
|
-
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should ==
|
194
|
+
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should == 2
|
193
195
|
ConcurrentRestrictionJob.decrement_running_count(ConcurrentRestrictionJob.tracking_key).should == false
|
194
|
-
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should ==
|
196
|
+
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should == 1
|
195
197
|
ConcurrentRestrictionJob.decrement_running_count(ConcurrentRestrictionJob.tracking_key).should == false
|
196
198
|
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should == 0
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should not decrement running count below 0" do
|
202
|
+
ConcurrentRestrictionJob.stub!(:concurrent_limit).and_return(1)
|
203
|
+
ConcurrentRestrictionJob.set_running_count(ConcurrentRestrictionJob.tracking_key, 0)
|
197
204
|
ConcurrentRestrictionJob.decrement_running_count(ConcurrentRestrictionJob.tracking_key).should == false
|
198
205
|
ConcurrentRestrictionJob.running_count(ConcurrentRestrictionJob.tracking_key).should == 0
|
199
206
|
end
|
data/spec/redis-test.conf
CHANGED
@@ -21,7 +21,7 @@ daemonize yes
|
|
21
21
|
pidfile ./redis.pid
|
22
22
|
|
23
23
|
# Accept connections on the specified port, default is 6379
|
24
|
-
port
|
24
|
+
port 6379
|
25
25
|
|
26
26
|
# If you want you can bind a single interface, if the bind option is not
|
27
27
|
# specified all the interfaces will listen for incoming connections.
|
@@ -143,41 +143,78 @@ describe Resque::Plugins::ConcurrentRestriction::Worker do
|
|
143
143
|
|
144
144
|
it "should run multiple jobs concurrently" do
|
145
145
|
7.times {|i| Resque.enqueue(MultipleConcurrentRestrictionJob, i) }
|
146
|
-
|
146
|
+
|
147
147
|
7.times do
|
148
148
|
unless child = fork
|
149
|
-
Resque.redis
|
149
|
+
Resque.redis.client.connect
|
150
150
|
run_resque_queue('*')
|
151
151
|
exit!
|
152
152
|
end
|
153
153
|
end
|
154
154
|
sleep 0.25
|
155
|
-
|
155
|
+
|
156
156
|
MultipleConcurrentRestrictionJob.total_run_count.should == 4
|
157
157
|
MultipleConcurrentRestrictionJob.running_count(MultipleConcurrentRestrictionJob.tracking_key).should == 4
|
158
158
|
MultipleConcurrentRestrictionJob.restriction_queue(MultipleConcurrentRestrictionJob.tracking_key, :normal).size.should == 3
|
159
|
-
|
159
|
+
|
160
160
|
Process.waitall
|
161
|
-
|
161
|
+
|
162
162
|
3.times do
|
163
163
|
unless child = fork
|
164
|
-
Resque.redis
|
164
|
+
Resque.redis.client.connect
|
165
165
|
run_resque_queue('*')
|
166
166
|
exit!
|
167
167
|
end
|
168
168
|
end
|
169
169
|
sleep 0.25
|
170
|
-
|
170
|
+
|
171
171
|
MultipleConcurrentRestrictionJob.total_run_count.should == 7
|
172
172
|
MultipleConcurrentRestrictionJob.running_count(MultipleConcurrentRestrictionJob.tracking_key).should == 3
|
173
173
|
MultipleConcurrentRestrictionJob.restriction_queue(MultipleConcurrentRestrictionJob.tracking_key, :normal).size.should == 0
|
174
|
-
|
174
|
+
|
175
175
|
Process.waitall
|
176
|
-
|
176
|
+
|
177
177
|
MultipleConcurrentRestrictionJob.running_count(MultipleConcurrentRestrictionJob.tracking_key).should == 0
|
178
178
|
MultipleConcurrentRestrictionJob.total_run_count.should == 7
|
179
179
|
end
|
180
180
|
|
181
|
+
it "should run only one concurrent job" do
|
182
|
+
5.times {|i| Resque.enqueue(OneConcurrentRestrictionJob, i) }
|
183
|
+
5.times do
|
184
|
+
unless child = fork
|
185
|
+
Resque.redis.client.connect
|
186
|
+
run_resque_queue('*')
|
187
|
+
exit!
|
188
|
+
end
|
189
|
+
end
|
190
|
+
sleep 0.25
|
191
|
+
|
192
|
+
OneConcurrentRestrictionJob.total_run_count.should == 1
|
193
|
+
OneConcurrentRestrictionJob.running_count(OneConcurrentRestrictionJob.tracking_key).should == 1
|
194
|
+
OneConcurrentRestrictionJob.restriction_queue(OneConcurrentRestrictionJob.tracking_key, :normal).size.should == 4
|
195
|
+
|
196
|
+
Process.waitall
|
197
|
+
|
198
|
+
2.times do
|
199
|
+
unless child = fork
|
200
|
+
Resque.redis.client.connect
|
201
|
+
run_resque_queue('*')
|
202
|
+
exit!
|
203
|
+
end
|
204
|
+
end
|
205
|
+
sleep 0.25
|
206
|
+
|
207
|
+
OneConcurrentRestrictionJob.total_run_count.should == 2
|
208
|
+
OneConcurrentRestrictionJob.running_count(OneConcurrentRestrictionJob.tracking_key).should == 1
|
209
|
+
OneConcurrentRestrictionJob.restriction_queue(OneConcurrentRestrictionJob.tracking_key, :normal).size.should == 3
|
210
|
+
|
211
|
+
Process.waitall
|
212
|
+
|
213
|
+
OneConcurrentRestrictionJob.running_count(OneConcurrentRestrictionJob.tracking_key).should == 0
|
214
|
+
OneConcurrentRestrictionJob.total_run_count.should == 2
|
215
|
+
|
216
|
+
end
|
217
|
+
|
181
218
|
it "should decrement execution number when concurrent job fails" do
|
182
219
|
run_resque_job(ConcurrentRestrictionJob, "bad")
|
183
220
|
Resque.redis.lrange("failed", 0, -1).size.should == 1
|
data/spec/spec_helper.rb
CHANGED
@@ -1,26 +1,33 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require 'ap'
|
3
3
|
|
4
|
-
spec_dir = File.dirname(File.expand_path(__FILE__))
|
5
|
-
REDIS_CMD = "redis-server #{spec_dir}/redis-test.conf"
|
6
|
-
|
7
|
-
puts "Starting redis for testing at localhost:9736..."
|
8
|
-
puts `cd #{spec_dir}; #{REDIS_CMD}`
|
9
|
-
|
10
|
-
require 'resque'
|
11
|
-
Resque.redis = 'localhost:9736'
|
12
4
|
require 'resque-concurrent-restriction'
|
13
5
|
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
6
|
+
# No need to start redis when running in Travis
|
7
|
+
unless ENV['CI']
|
8
|
+
|
9
|
+
begin
|
10
|
+
Resque.queues
|
11
|
+
rescue Errno::ECONNREFUSED
|
12
|
+
spec_dir = File.dirname(File.expand_path(__FILE__))
|
13
|
+
REDIS_CMD = "redis-server #{spec_dir}/redis-test.conf"
|
14
|
+
|
15
|
+
puts "Starting redis for testing at localhost..."
|
16
|
+
puts `cd #{spec_dir}; #{REDIS_CMD}`
|
17
|
+
|
18
|
+
# Schedule the redis server for shutdown when tests are all finished.
|
19
|
+
at_exit do
|
20
|
+
puts 'Stopping redis'
|
21
|
+
pid = File.read("#{spec_dir}/redis.pid").to_i rescue nil
|
22
|
+
system ("kill -9 #{pid}") if pid.to_i != 0
|
23
|
+
File.delete("#{spec_dir}/redis.pid") rescue nil
|
24
|
+
File.delete("#{spec_dir}/redis-server.log") rescue nil
|
25
|
+
File.delete("#{spec_dir}/dump.rdb") rescue nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
21
29
|
end
|
22
30
|
|
23
|
-
|
24
31
|
##
|
25
32
|
# Helper to perform job classes
|
26
33
|
#
|
@@ -160,3 +167,15 @@ class MultipleConcurrentRestrictionJob
|
|
160
167
|
sleep 0.5
|
161
168
|
end
|
162
169
|
end
|
170
|
+
|
171
|
+
class OneConcurrentRestrictionJob
|
172
|
+
extend RunCountHelper
|
173
|
+
extend Resque::Plugins::ConcurrentRestriction
|
174
|
+
concurrent 1
|
175
|
+
|
176
|
+
@queue = 'normal'
|
177
|
+
|
178
|
+
def self.perform(*args)
|
179
|
+
sleep 0.5
|
180
|
+
end
|
181
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque-concurrent-restriction
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
default_executable:
|
12
|
+
date: 2012-04-23 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: resque
|
17
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
18
17
|
none: false
|
19
18
|
requirements:
|
20
19
|
- - ~>
|
@@ -22,10 +21,31 @@ dependencies:
|
|
22
21
|
version: '1.10'
|
23
22
|
type: :runtime
|
24
23
|
prerelease: false
|
25
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.10'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: json
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
26
46
|
- !ruby/object:Gem::Dependency
|
27
47
|
name: rspec
|
28
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
29
49
|
none: false
|
30
50
|
requirements:
|
31
51
|
- - ~>
|
@@ -33,10 +53,31 @@ dependencies:
|
|
33
53
|
version: '2.5'
|
34
54
|
type: :development
|
35
55
|
prerelease: false
|
36
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.5'
|
37
62
|
- !ruby/object:Gem::Dependency
|
38
63
|
name: awesome_print
|
39
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: json
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
40
81
|
none: false
|
41
82
|
requirements:
|
42
83
|
- - ! '>='
|
@@ -44,7 +85,12 @@ dependencies:
|
|
44
85
|
version: '0'
|
45
86
|
type: :development
|
46
87
|
prerelease: false
|
47
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
48
94
|
description: A resque plugin for limiting how many of a specific job can run concurrently
|
49
95
|
email:
|
50
96
|
- matt@conwaysplace.com
|
@@ -53,6 +99,7 @@ extensions: []
|
|
53
99
|
extra_rdoc_files: []
|
54
100
|
files:
|
55
101
|
- .gitignore
|
102
|
+
- .travis.yml
|
56
103
|
- Gemfile
|
57
104
|
- LICENSE
|
58
105
|
- README.md
|
@@ -67,7 +114,6 @@ files:
|
|
67
114
|
- spec/resque_worker_extensions_spec.rb
|
68
115
|
- spec/spec.opts
|
69
116
|
- spec/spec_helper.rb
|
70
|
-
has_rdoc: true
|
71
117
|
homepage: http://github.com/wr0ngway/resque-concurrent-restriction
|
72
118
|
licenses: []
|
73
119
|
post_install_message:
|
@@ -88,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
134
|
version: '0'
|
89
135
|
requirements: []
|
90
136
|
rubyforge_project: resque-concurrent-restriction
|
91
|
-
rubygems_version: 1.
|
137
|
+
rubygems_version: 1.8.21
|
92
138
|
signing_key:
|
93
139
|
specification_version: 3
|
94
140
|
summary: A resque plugin for limiting how many of a specific job can run concurrently
|
@@ -98,3 +144,4 @@ test_files:
|
|
98
144
|
- spec/resque_worker_extensions_spec.rb
|
99
145
|
- spec/spec.opts
|
100
146
|
- spec/spec_helper.rb
|
147
|
+
has_rdoc:
|