take2 0.0.5 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +8 -2
- data/lib/take2.rb +34 -31
- data/lib/take2/version.rb +1 -1
- data/spec/take2_spec.rb +92 -94
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2b9d1165c2bbc7d0e0e59b161ef35e9d72586f8498738312bf72ebf5e5b2f31
|
4
|
+
data.tar.gz: 1b4d00168ff6b2cdc14be86fcf65b05e0ff919ca4e61535e76cdd3fac0006680
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f01b351dd0a3640fd09d7fe00b515543bbbfaf9ec1abb60bbf2b962e20b32490edb06cab51b81ee65383864e90f92e54533639a1bed1eaae1ed24afe599e378
|
7
|
+
data.tar.gz: 853ffe970c1c08306ff42966d7946ed92445e7d6b999801eeedf9ff2eae4f0ef12e321ff9ab75a2ce22d9514af5797d497c9f090dfee4aa4be7e7a7809911e64
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -30,7 +30,12 @@ class KratosService
|
|
30
30
|
# Defines callable code to run before next retry. Could be an out put to some logger.
|
31
31
|
on_retry proc { |error, tries| puts "#{self.name} - Retrying.. #{tries} of #{self.retriable_configuration[:retries]} (#{error})" }
|
32
32
|
|
33
|
-
|
33
|
+
# The available strategies are:
|
34
|
+
# type :constant, start: 2 => [2, 2, 2, 2 ... ]
|
35
|
+
# type :linear, start: 3, factor: 2 => [3, 6, 12, 24 ... ]
|
36
|
+
# type :fibonacci, start: 2 => [2, 3, 5, 8, 13 ... ]
|
37
|
+
# type :exponential, start: 3 => [3, 7, 12, 28, 47 ... ]
|
38
|
+
backoff_strategy type: :fibonacci, start: 3
|
34
39
|
|
35
40
|
def call_boy
|
36
41
|
call_api_with_retry do
|
@@ -45,7 +50,7 @@ class KratosService
|
|
45
50
|
# Pass custom options per method call
|
46
51
|
# The class defaults will not be overwritten
|
47
52
|
def kill_baldur
|
48
|
-
call_api_with_retry(retries: 2, retriable: [IOError], retry_proc: proc {}, retry_condition_proc: proc {}
|
53
|
+
call_api_with_retry(retries: 2, retriable: [IOError], retry_proc: proc {}, retry_condition_proc: proc {}) do
|
49
54
|
# Some logic that might raise..
|
50
55
|
end
|
51
56
|
end
|
@@ -88,5 +93,6 @@ Take2.configure do |config|
|
|
88
93
|
config.retry_condition_proc = proc {false}
|
89
94
|
config.time_to_sleep = nil
|
90
95
|
config.retry_proc = proc {Rails.logger.info "Retry message"}
|
96
|
+
config.backoff_intervals = Take2::Backoff.new(:linear, 1).intervals
|
91
97
|
end
|
92
98
|
```
|
data/lib/take2.rb
CHANGED
@@ -13,22 +13,22 @@ module Take2
|
|
13
13
|
|
14
14
|
class << self
|
15
15
|
attr_accessor :configuration
|
16
|
-
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
def config
|
18
|
+
@configuration ||= Configuration.new
|
19
|
+
end
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
def reset(options = {})
|
22
|
+
@configuration = Configuration.new(options)
|
23
|
+
end
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
def local_defaults(options)
|
26
|
+
configuration.validate_options(options)
|
27
|
+
end
|
29
28
|
|
30
|
-
|
31
|
-
|
29
|
+
def configure
|
30
|
+
yield(config) if block_given?
|
31
|
+
end
|
32
32
|
end
|
33
33
|
|
34
34
|
module InstanceMethods
|
@@ -56,8 +56,16 @@ module Take2
|
|
56
56
|
# end
|
57
57
|
#
|
58
58
|
# end
|
59
|
+
def call_api_with_retry(options = {}, &block)
|
60
|
+
self.class.call_api_with_retry(options, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
alias_method :with_retry, :call_api_with_retry
|
64
|
+
end
|
65
|
+
|
66
|
+
module ClassMethods
|
59
67
|
def call_api_with_retry(options = {})
|
60
|
-
config =
|
68
|
+
config = retriable_configuration
|
61
69
|
config.merge!(Take2.local_defaults(options)) unless options.empty?
|
62
70
|
tries ||= config[:retries]
|
63
71
|
begin
|
@@ -74,25 +82,7 @@ module Take2
|
|
74
82
|
raise e
|
75
83
|
end
|
76
84
|
end
|
77
|
-
alias_method :with_retry, :call_api_with_retry
|
78
85
|
|
79
|
-
private
|
80
|
-
|
81
|
-
def rest(config, tries)
|
82
|
-
seconds = if config[:time_to_sleep].to_f > 0
|
83
|
-
config[:time_to_sleep].to_f
|
84
|
-
else
|
85
|
-
next_interval(config[:backoff_intervals], config[:retries], tries)
|
86
|
-
end
|
87
|
-
sleep(seconds)
|
88
|
-
end
|
89
|
-
|
90
|
-
def next_interval(intervals, retries, current)
|
91
|
-
intervals[retries - current]
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
module ClassMethods
|
96
86
|
# Sets number of retries.
|
97
87
|
#
|
98
88
|
# Example:
|
@@ -197,5 +187,18 @@ module Take2
|
|
197
187
|
return response.status if response.respond_to?(:status)
|
198
188
|
response.status_code if response.respond_to?(:status_code)
|
199
189
|
end
|
190
|
+
|
191
|
+
def rest(config, tries)
|
192
|
+
seconds = if config[:time_to_sleep].to_f > 0
|
193
|
+
config[:time_to_sleep].to_f
|
194
|
+
else
|
195
|
+
next_interval(config[:backoff_intervals], config[:retries], tries)
|
196
|
+
end
|
197
|
+
sleep(seconds)
|
198
|
+
end
|
199
|
+
|
200
|
+
def next_interval(intervals, retries, current)
|
201
|
+
intervals[retries - current]
|
202
|
+
end
|
200
203
|
end
|
201
204
|
end
|
data/lib/take2/version.rb
CHANGED
data/spec/take2_spec.rb
CHANGED
@@ -151,132 +151,130 @@ RSpec.describe(Take2) do
|
|
151
151
|
raise error
|
152
152
|
end
|
153
153
|
|
154
|
-
|
155
|
-
let(:
|
156
|
-
|
154
|
+
describe 'class method' do
|
155
|
+
let(:retriable_error) { Net::HTTPRetriableError.new('Release the Kraken...many times!!', nil) }
|
157
156
|
before(:each) { @tries = 0 }
|
158
|
-
|
159
|
-
|
160
|
-
expect do
|
161
|
-
object.call_api_with_retry { wrath_the_gods_with error }
|
162
|
-
end.to(raise_error(error.class))
|
157
|
+
it 'responds to the method' do
|
158
|
+
expect(klass).to respond_to(:call_api_with_retry)
|
163
159
|
end
|
164
|
-
|
165
|
-
it 'is not retried' do
|
160
|
+
it 'retries correct number of times' do
|
166
161
|
expect do
|
167
|
-
|
168
|
-
end.to(change { @tries }.from(0).to(1))
|
162
|
+
klass.call_api_with_retry { wrath_the_gods_with retriable_error }
|
163
|
+
end.to(change { @tries }.from(0).to(klass.retriable_configuration[:retries] + 1))
|
169
164
|
rescue
|
170
165
|
nil
|
171
166
|
end
|
172
167
|
end
|
168
|
+
describe 'instance method' do
|
169
|
+
context 'when raised with non retriable error' do
|
170
|
+
let(:error) { StandardError.new('Release the Kraken!!') }
|
173
171
|
|
174
|
-
|
175
|
-
let(:retriable_error) { Net::HTTPRetriableError.new('Release the Kraken...many times!!', nil) }
|
176
|
-
|
177
|
-
before(:each) { @tries = 0 }
|
172
|
+
before(:each) { @tries = 0 }
|
178
173
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
nil
|
185
|
-
end
|
174
|
+
it 're raises the original error' do
|
175
|
+
expect do
|
176
|
+
object.call_api_with_retry { wrath_the_gods_with error }
|
177
|
+
end.to(raise_error(error.class))
|
178
|
+
end
|
186
179
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
.
|
191
|
-
begin
|
192
|
-
object.call_api_with_retry { wrath_the_gods_with retriable_error }
|
180
|
+
it 'is not retried' do
|
181
|
+
expect do
|
182
|
+
object.call_api_with_retry { wrath_the_gods_with error }
|
183
|
+
end.to(change { @tries }.from(0).to(1))
|
193
184
|
rescue
|
194
185
|
nil
|
195
186
|
end
|
196
187
|
end
|
197
188
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
189
|
+
context 'when raised with retriable error' do
|
190
|
+
let(:retriable_error) { Net::HTTPRetriableError.new('Release the Kraken...many times!!', nil) }
|
191
|
+
|
192
|
+
before(:each) { @tries = 0 }
|
193
|
+
|
194
|
+
it 'retries correct number of times' do
|
195
|
+
expect do
|
196
|
+
object.call_api_with_retry { wrath_the_gods_with retriable_error }
|
197
|
+
end.to(change { @tries }.from(0).to(klass.retriable_configuration[:retries] + 1))
|
204
198
|
rescue
|
205
199
|
nil
|
206
200
|
end
|
207
|
-
end
|
208
201
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
202
|
+
it 'calls the retry proc' do
|
203
|
+
expect(klass.retriable_configuration[:retry_proc])
|
204
|
+
.to(receive(:call)
|
205
|
+
.exactly(klass.retriable_configuration[:retries]))
|
206
|
+
begin
|
207
|
+
object.call_api_with_retry { wrath_the_gods_with retriable_error }
|
208
|
+
rescue
|
209
|
+
nil
|
210
|
+
end
|
211
|
+
end
|
217
212
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
213
|
+
it 'calls the retry_condition proc' do
|
214
|
+
expect(klass.retriable_configuration[:retry_condition_proc])
|
215
|
+
.to(receive(:call)
|
216
|
+
.exactly(klass.retriable_configuration[:retries]))
|
217
|
+
begin
|
218
|
+
object.call_api_with_retry { wrath_the_gods_with retriable_error }
|
219
|
+
rescue
|
220
|
+
nil
|
221
|
+
end
|
222
|
+
end
|
224
223
|
|
225
|
-
|
226
|
-
|
227
|
-
|
224
|
+
it 're raises the original error' do
|
225
|
+
expect do
|
226
|
+
object.call_api_with_retry { wrath_the_gods_with retriable_error }
|
227
|
+
end.to(raise_error(retriable_error.class))
|
228
|
+
end
|
229
|
+
end
|
228
230
|
|
229
|
-
|
231
|
+
context 'with custom options' do
|
232
|
+
let(:retriable_error) { Net::HTTPRetriableError.new('Release the Kraken...many times!!', nil) }
|
233
|
+
let(:new_retriable_error) { IOError.new('You shall not PASS!') }
|
230
234
|
|
231
|
-
|
232
|
-
expect do
|
233
|
-
object.call_api_with_retry(retries: 3) { wrath_the_gods_with retriable_error }
|
234
|
-
end.to(change { @tries }.from(0).to(4))
|
235
|
-
rescue
|
236
|
-
nil
|
237
|
-
end
|
235
|
+
before(:each) { @tries = 0 }
|
238
236
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
object.call_api_with_retry(retry_proc: new_proc) { wrath_the_gods_with retriable_error }
|
237
|
+
it 'overwrites the :retries' do
|
238
|
+
expect do
|
239
|
+
object.call_api_with_retry(retries: 3) { wrath_the_gods_with retriable_error }
|
240
|
+
end.to(change { @tries }.from(0).to(4))
|
244
241
|
rescue
|
245
242
|
nil
|
246
243
|
end
|
247
|
-
end
|
248
244
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
245
|
+
it 'overwrites the :retry_proc' do
|
246
|
+
new_proc = proc { 1**1 }
|
247
|
+
expect(new_proc).to(receive(:call).exactly(klass.retriable_configuration[:retries]))
|
248
|
+
begin
|
249
|
+
object.call_api_with_retry(retry_proc: new_proc) { wrath_the_gods_with retriable_error }
|
250
|
+
rescue
|
251
|
+
nil
|
252
|
+
end
|
256
253
|
end
|
257
|
-
end
|
258
254
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
255
|
+
it 'overwrites the :retry_condition_proc' do
|
256
|
+
new_proc = proc { true }
|
257
|
+
expect(new_proc).to(receive(:call).exactly(klass.retriable_configuration[:retries]))
|
258
|
+
begin
|
259
|
+
object.call_api_with_retry(retry_condition_proc: new_proc) { wrath_the_gods_with retriable_error }
|
260
|
+
rescue
|
261
|
+
nil
|
262
|
+
end
|
263
|
+
end
|
267
264
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
265
|
+
it 'overwrites the :retriable' do
|
266
|
+
expect do
|
267
|
+
object.call_api_with_retry(retriable: [new_retriable_error]) { wrath_the_gods_with retriable_error }
|
268
|
+
end.to(change { @tries }.from(0).to(1))
|
269
|
+
rescue
|
270
|
+
nil
|
271
|
+
end
|
275
272
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
273
|
+
it 'raises ArgumentError if there are invalid keys' do
|
274
|
+
expect do
|
275
|
+
object.call_api_with_retry(invalid_key: :nope) { wrath_the_gods_with retriable_error }
|
276
|
+
end.to(raise_error(ArgumentError))
|
277
|
+
end
|
280
278
|
end
|
281
279
|
end
|
282
280
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: take2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton Magids
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Retry API calls, methods or blocks of code. Define take2 retry behavior
|
14
14
|
or use defaults and you good to go.
|
@@ -58,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
58
|
version: '0'
|
59
59
|
requirements: []
|
60
60
|
rubyforge_project:
|
61
|
-
rubygems_version: 2.7.
|
61
|
+
rubygems_version: 2.7.9
|
62
62
|
signing_key:
|
63
63
|
specification_version: 4
|
64
64
|
summary: Provides Take2 for your APIs calls
|