kestrel-client 0.5.3 → 0.5.7
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/kestrel-client.gemspec +2 -2
- data/lib/kestrel/client/transactional.rb +23 -29
- data/spec/kestrel/client/transactional_spec.rb +130 -55
- metadata +4 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.7
|
data/kestrel-client.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{kestrel-client}
|
8
|
-
s.version = "0.5.
|
8
|
+
s.version = "0.5.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Matt Freels", "Rael Dornfest"]
|
12
|
-
s.date = %q{2010-10-
|
12
|
+
s.date = %q{2010-10-06}
|
13
13
|
s.description = %q{Ruby client for the Kestrel queue server}
|
14
14
|
s.email = %q{rael@twitter.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -34,9 +34,7 @@ class Kestrel::Client::Transactional < Kestrel::Client::Proxy
|
|
34
34
|
|
35
35
|
# Returns job from the +key+ queue 1 - ERROR_PROCESSING_RATE
|
36
36
|
# pct. of the time. Every so often, checks the error queue for
|
37
|
-
# jobs and returns a retryable job.
|
38
|
-
# +key+ queue are empty, attempts to pull a job from the
|
39
|
-
# alternate queue before giving up.
|
37
|
+
# jobs and returns a retryable job.
|
40
38
|
#
|
41
39
|
# ==== Returns
|
42
40
|
# Job, possibly retryable, or nil
|
@@ -44,21 +42,27 @@ class Kestrel::Client::Transactional < Kestrel::Client::Proxy
|
|
44
42
|
def get(key, opts = {})
|
45
43
|
raise MultipleQueueException if current_queue && key != current_queue
|
46
44
|
|
47
|
-
|
45
|
+
close_last_transaction
|
48
46
|
|
49
|
-
|
47
|
+
queue = read_from_error_queue? ? key + "_errors" : key
|
50
48
|
|
51
|
-
if job =
|
52
|
-
@current_queue = key
|
49
|
+
if job = client.get(queue, opts.merge(:open => true))
|
53
50
|
@job = job.is_a?(RetryableJob) ? job : RetryableJob.new(0, job)
|
51
|
+
@last_read_queue = queue
|
52
|
+
@current_queue = key
|
54
53
|
@job.job
|
55
|
-
else
|
56
|
-
@current_queue = @job = nil
|
57
54
|
end
|
58
55
|
end
|
59
56
|
|
60
57
|
def current_try
|
61
|
-
@job
|
58
|
+
@job.retries + 1
|
59
|
+
end
|
60
|
+
|
61
|
+
def close_last_transaction #:nodoc:
|
62
|
+
return unless @last_read_queue
|
63
|
+
|
64
|
+
client.get_from_last(@last_read_queue + "/close")
|
65
|
+
@last_read_queue = @current_queue = @job = nil
|
62
66
|
end
|
63
67
|
|
64
68
|
# Enqueues the current job on the error queue for later
|
@@ -66,41 +70,31 @@ class Kestrel::Client::Transactional < Kestrel::Client::Proxy
|
|
66
70
|
# gives up entirely.
|
67
71
|
#
|
68
72
|
# ==== Returns
|
69
|
-
# Boolean:: true if the job is
|
73
|
+
# Boolean:: true if the job is enqueued in the retry queue, false otherwise
|
74
|
+
#
|
70
75
|
#
|
71
76
|
def retry(item = nil)
|
72
77
|
job =
|
73
78
|
if item
|
74
|
-
current_retries = (@job ?
|
79
|
+
current_retries = (@job ? @job.retries : 0)
|
75
80
|
RetryableJob.new(current_retries, item)
|
76
81
|
else
|
77
|
-
@job
|
82
|
+
@job.dup
|
78
83
|
end
|
79
84
|
|
80
85
|
return unless job
|
81
86
|
|
82
87
|
job.retries += 1
|
83
88
|
|
84
|
-
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
# close the transaction on the original queue if this is the first retry
|
89
|
-
close_transaction(job.retries == 1 ? current_queue : "#{current_queue}_errors")
|
89
|
+
client.set(current_queue + "_errors", job) if job.retries < @max_retries
|
90
|
+
close_last_transaction
|
90
91
|
|
91
|
-
|
92
|
+
job.retries < @max_retries
|
92
93
|
end
|
93
94
|
|
94
95
|
private
|
95
96
|
|
96
|
-
|
97
|
-
|
98
|
-
#
|
99
|
-
def get_with_fallback(primary, secondary, opts) #:nodoc:
|
100
|
-
client.get(primary, opts) || client.get(secondary, opts)
|
101
|
-
end
|
102
|
-
|
103
|
-
def close_transaction(key) #:nodoc:
|
104
|
-
client.get_from_last("#{key}/close")
|
97
|
+
def read_from_error_queue?
|
98
|
+
rand < @error_rate
|
105
99
|
end
|
106
100
|
end
|
@@ -1,52 +1,111 @@
|
|
1
1
|
require 'spec/spec_helper'
|
2
2
|
|
3
3
|
describe "Kestrel::Client::Transactional" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
before do
|
5
|
+
@raw_kestrel_client = Kestrel::Client.new(*Kestrel::Config.default)
|
6
|
+
@kestrel = Kestrel::Client::Transactional.new(@raw_kestrel_client)
|
7
|
+
@queue = "some_queue"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "integration" do
|
11
|
+
def get_job
|
12
|
+
job = nil
|
13
|
+
job = @kestrel.get(@queue) until job
|
14
|
+
job
|
10
15
|
end
|
11
16
|
|
12
|
-
|
17
|
+
it "processes normal jobs" do
|
18
|
+
returns = [:mcguffin]
|
19
|
+
stub(@raw_kestrel_client).get(@queue, anything) { returns.shift }
|
20
|
+
stub(@raw_kestrel_client).get(@queue + "_errors", anything)
|
21
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "/close")
|
13
22
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
23
|
+
get_job.should == :mcguffin
|
24
|
+
@kestrel.current_try.should == 1
|
25
|
+
@kestrel.get(@queue) # simulate next get run
|
26
|
+
end
|
18
27
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
28
|
+
it "processes successful retries" do
|
29
|
+
returns = [Kestrel::Client::Transactional::RetryableJob.new(1, :mcguffin)]
|
30
|
+
stub(@raw_kestrel_client).get(@queue + "_errors", anything) { returns.shift }
|
31
|
+
stub(@raw_kestrel_client).get(@queue, anything)
|
32
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "_errors/close")
|
33
|
+
|
34
|
+
get_job.should == :mcguffin
|
35
|
+
@kestrel.current_try.should == 2
|
36
|
+
@kestrel.get(@queue) # simulate next get run
|
37
|
+
end
|
38
|
+
|
39
|
+
it "processes normal jobs that should retry" do
|
40
|
+
returns = [:mcguffin]
|
41
|
+
stub(@raw_kestrel_client).get(@queue, anything) { returns.shift }
|
42
|
+
stub(@raw_kestrel_client).get(@queue + "_errors", anything)
|
43
|
+
mock(@raw_kestrel_client).set(@queue + "_errors", anything) do |q,j|
|
44
|
+
j.retries.should == 1
|
45
|
+
j.job.should == :mcguffin
|
24
46
|
end
|
47
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "/close")
|
25
48
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
49
|
+
get_job.should == :mcguffin
|
50
|
+
@kestrel.current_try.should == 1
|
51
|
+
|
52
|
+
@kestrel.retry
|
53
|
+
@kestrel.get(@queue) # simulate next get run
|
54
|
+
end
|
55
|
+
|
56
|
+
it "processes retries that should retry" do
|
57
|
+
returns = [Kestrel::Client::Transactional::RetryableJob.new(1, :mcguffin)]
|
58
|
+
stub(@raw_kestrel_client).get(@queue + "_errors", anything) { returns.shift }
|
59
|
+
stub(@raw_kestrel_client).get(@queue, anything)
|
60
|
+
mock(@raw_kestrel_client).set(@queue + "_errors", anything) do |q,j|
|
61
|
+
j.retries.should == 2
|
62
|
+
j.job.should == :mcguffin
|
31
63
|
end
|
64
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "_errors/close")
|
32
65
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
66
|
+
get_job.should == :mcguffin
|
67
|
+
@kestrel.current_try.should == 2
|
68
|
+
|
69
|
+
@kestrel.retry
|
70
|
+
@kestrel.get(@queue) # simulate next get run
|
71
|
+
end
|
72
|
+
|
73
|
+
it "processes retries that should give up" do
|
74
|
+
returns = [Kestrel::Client::Transactional::RetryableJob.new(Kestrel::Client::Transactional::DEFAULT_RETRIES - 1, :mcguffin)]
|
75
|
+
stub(@raw_kestrel_client).get(@queue + "_errors", anything) { returns.shift }
|
76
|
+
stub(@raw_kestrel_client).get(@queue, anything)
|
77
|
+
mock(@raw_kestrel_client).set.never
|
78
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "_errors/close")
|
79
|
+
|
80
|
+
get_job.should == :mcguffin
|
81
|
+
@kestrel.current_try.should == Kestrel::Client::Transactional::DEFAULT_RETRIES
|
82
|
+
|
83
|
+
@kestrel.retry
|
84
|
+
@kestrel.get(@queue) # simulate next get run
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "Instance Methods" do
|
89
|
+
before do
|
90
|
+
stub(@kestrel).rand { 1 }
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#get" do
|
94
|
+
it "asks for a transaction" do
|
95
|
+
mock(@raw_kestrel_client).get(@queue, :open => true) { :mcguffin }
|
37
96
|
@kestrel.get(@queue).should == :mcguffin
|
38
97
|
end
|
39
98
|
|
40
|
-
it "
|
99
|
+
it "is nil when the primary queue is empty and selected" do
|
41
100
|
mock(@kestrel).rand { Kestrel::Client::Transactional::ERROR_PROCESSING_RATE + 0.05 }
|
42
101
|
mock(@raw_kestrel_client).get(@queue, anything) { nil }
|
43
|
-
mock(@raw_kestrel_client).get(@queue + "_errors", anything)
|
44
|
-
@kestrel.get(@queue).should
|
102
|
+
mock(@raw_kestrel_client).get(@queue + "_errors", anything).never
|
103
|
+
@kestrel.get(@queue).should be_nil
|
45
104
|
end
|
46
105
|
|
47
|
-
it "is nil when
|
48
|
-
mock(@kestrel).rand { Kestrel::Client::Transactional::ERROR_PROCESSING_RATE
|
49
|
-
mock(@raw_kestrel_client).get(@queue, anything)
|
106
|
+
it "is nil when the error queue is empty and selected" do
|
107
|
+
mock(@kestrel).rand { Kestrel::Client::Transactional::ERROR_PROCESSING_RATE - 0.05 }
|
108
|
+
mock(@raw_kestrel_client).get(@queue, anything).never
|
50
109
|
mock(@raw_kestrel_client).get(@queue + "_errors", anything) { nil }
|
51
110
|
@kestrel.get(@queue).should be_nil
|
52
111
|
end
|
@@ -58,7 +117,6 @@ describe "Kestrel::Client::Transactional" do
|
|
58
117
|
end
|
59
118
|
|
60
119
|
@kestrel.get(@queue).should == :mcmuffin
|
61
|
-
@kestrel.current_try.should == 2
|
62
120
|
end
|
63
121
|
|
64
122
|
it "closes an open transaction with no retries" do
|
@@ -90,29 +148,6 @@ describe "Kestrel::Client::Transactional" do
|
|
90
148
|
end
|
91
149
|
end
|
92
150
|
|
93
|
-
describe "#current_try" do
|
94
|
-
|
95
|
-
it "returns 1 if nothing has been gotten" do
|
96
|
-
@kestrel.current_try.should == 1
|
97
|
-
end
|
98
|
-
|
99
|
-
it "returns 1 for jobs that have not been retried" do
|
100
|
-
mock(@raw_kestrel_client).get(@queue, anything) { :mcguffin }
|
101
|
-
@kestrel.get(@queue)
|
102
|
-
@kestrel.current_try.should == 1
|
103
|
-
end
|
104
|
-
|
105
|
-
it "returns 1 plus the number of tries for a RetryableJob" do
|
106
|
-
stub(@kestrel).rand { 0 }
|
107
|
-
mock(@raw_kestrel_client).get(@queue + "_errors", anything) do
|
108
|
-
Kestrel::Client::Transactional::RetryableJob.new(1, :mcmuffin)
|
109
|
-
end
|
110
|
-
@kestrel.get(@queue)
|
111
|
-
@kestrel.current_try.should == 2
|
112
|
-
end
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
151
|
describe "#retry" do
|
117
152
|
before do
|
118
153
|
stub(@raw_kestrel_client).get(@queue, anything) { :mcmuffin }
|
@@ -157,6 +192,7 @@ describe "Kestrel::Client::Transactional" do
|
|
157
192
|
Kestrel::Client::Transactional::RetryableJob.new(Kestrel::Client::Transactional::DEFAULT_RETRIES - 1, :mcmuffin)
|
158
193
|
end
|
159
194
|
mock(@raw_kestrel_client).set(@queue + "_errors", anything).never
|
195
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "_errors/close")
|
160
196
|
@kestrel.get(@queue)
|
161
197
|
@kestrel.retry.should be_false
|
162
198
|
end
|
@@ -179,7 +215,46 @@ describe "Kestrel::Client::Transactional" do
|
|
179
215
|
mock(@raw_kestrel_client).get_from_last(@queue + "_errors/close")
|
180
216
|
@kestrel.retry
|
181
217
|
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "#read_from_error_queue?" do
|
221
|
+
it "returns the error queue ERROR_PROCESSING_RATE pct. of the time" do
|
222
|
+
mock(@kestrel).rand { Kestrel::Client::Transactional::ERROR_PROCESSING_RATE - 0.05 }
|
223
|
+
@kestrel.send(:read_from_error_queue?).should == true
|
224
|
+
end
|
225
|
+
|
226
|
+
it "returns the normal queue most of the time" do
|
227
|
+
mock(@kestrel).rand { Kestrel::Client::Transactional::ERROR_PROCESSING_RATE + 0.05 }
|
228
|
+
@kestrel.send(:read_from_error_queue?).should == false
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "#close_last_transaction" do
|
233
|
+
it "does nothing if there is no last transaction" do
|
234
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "/close").never
|
235
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "_errors/close").never
|
236
|
+
@kestrel.send(:close_last_transaction)
|
237
|
+
end
|
182
238
|
|
239
|
+
it "closes the normal queue if the job was pulled off of the normal queue" do
|
240
|
+
mock(@kestrel).read_from_error_queue? { false }
|
241
|
+
mock(@raw_kestrel_client).get(@queue, :open => true) { :mcguffin }
|
242
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "/close")
|
243
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "_errors/close").never
|
244
|
+
|
245
|
+
@kestrel.get(@queue).should == :mcguffin
|
246
|
+
@kestrel.send(:close_last_transaction)
|
247
|
+
end
|
248
|
+
|
249
|
+
it "closes the error queue if the job was pulled off of the error queue" do
|
250
|
+
mock(@kestrel).read_from_error_queue? { true }
|
251
|
+
mock(@raw_kestrel_client).get(@queue + "_errors", anything) { Kestrel::Client::Transactional::RetryableJob.new 1, :mcguffin }
|
252
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "/close").never
|
253
|
+
mock(@raw_kestrel_client).get_from_last(@queue + "_errors/close")
|
254
|
+
|
255
|
+
@kestrel.get(@queue).should == :mcguffin
|
256
|
+
@kestrel.send(:close_last_transaction)
|
257
|
+
end
|
183
258
|
end
|
184
259
|
end
|
185
260
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kestrel-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 0.5.
|
9
|
+
- 7
|
10
|
+
version: 0.5.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Matt Freels
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-10-
|
19
|
+
date: 2010-10-06 00:00:00 -07:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|