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 CHANGED
@@ -1 +1 @@
1
- 0.5.3
1
+ 0.5.7
@@ -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.3"
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-05}
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. If either the error queue or
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
- close_transaction(current_try == 1 ? key : "#{key}_errors")
45
+ close_last_transaction
48
46
 
49
- q1, q2 = (rand < @error_rate) ? [key + "_errors", key] : [key, key + "_errors"]
47
+ queue = read_from_error_queue? ? key + "_errors" : key
50
48
 
51
- if job = get_with_fallback(q1, q2, opts.merge(:close => true, :open => true))
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 ? @job.retries + 1 : 1
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 retryable, false otherwise
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 ? @job.retries : 0)
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
- if should_retry = job.retries < @max_retries
85
- client.set(current_queue + "_errors", job)
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
- should_retry
92
+ job.retries < @max_retries
92
93
  end
93
94
 
94
95
  private
95
96
 
96
- # If a get against the +primary+ queue is nil, falls back to the
97
- # +secondary+ queue.
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
- describe "Instance Methods" do
5
- before do
6
- @raw_kestrel_client = Kestrel::Client.new(*Kestrel::Config.default)
7
- @kestrel = Kestrel::Client::Transactional.new(@raw_kestrel_client)
8
- stub(@kestrel).rand { 1 }
9
- @queue = "some_queue"
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
- describe "#get" do
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
- it "asks for a transaction" do
15
- mock(@raw_kestrel_client).get(@queue, :open => true, :close => true) { :mcguffin }
16
- @kestrel.get(@queue).should == :mcguffin
17
- end
23
+ get_job.should == :mcguffin
24
+ @kestrel.current_try.should == 1
25
+ @kestrel.get(@queue) # simulate next get run
26
+ end
18
27
 
19
- it "gets from the error queue ERROR_PROCESSING_RATE pct. of the time" do
20
- mock(@kestrel).rand { Kestrel::Client::Transactional::ERROR_PROCESSING_RATE - 0.05 }
21
- mock(@raw_kestrel_client).get(@queue + "_errors", anything) { :mcguffin }
22
- mock(@raw_kestrel_client).get(@queue, anything).never
23
- @kestrel.get(@queue).should == :mcguffin
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
- it "falls through to the normal queue when error queue is empty" do
27
- mock(@kestrel).rand { Kestrel::Client::Transactional::ERROR_PROCESSING_RATE - 0.05 }
28
- mock(@raw_kestrel_client).get(@queue + "_errors", anything) { nil }
29
- mock(@raw_kestrel_client).get(@queue, anything) { :mcguffin }
30
- @kestrel.get(@queue).should == :mcguffin
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
- it "gets from the normal queue most of the time" do
34
- mock(@kestrel).rand { Kestrel::Client::Transactional::ERROR_PROCESSING_RATE + 0.05 }
35
- mock(@raw_kestrel_client).get(@queue, anything) { :mcguffin }
36
- mock(@raw_kestrel_client).get(@queue + "_errors", anything).never
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 "falls through to the error queue when normal queue is empty" do
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) { :mcguffin }
44
- @kestrel.get(@queue).should == :mcguffin
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 both queues are empty" do
48
- mock(@kestrel).rand { Kestrel::Client::Transactional::ERROR_PROCESSING_RATE + 0.05 }
49
- mock(@raw_kestrel_client).get(@queue, anything) { nil }
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: 13
4
+ hash: 5
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 5
9
- - 3
10
- version: 0.5.3
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-05 00:00:00 -07:00
19
+ date: 2010-10-06 00:00:00 -07:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency