kestrel-client 0.5.3 → 0.5.7
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/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
|