take2 0.0.3 → 1.0.0
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.
- checksums.yaml +5 -5
- data/.circleci/config.yml +1 -1
- data/.gitignore +3 -0
- data/.hound.yml +3 -0
- data/.rubocop.yml +1201 -0
- data/CHANGELOG.md +10 -1
- data/Gemfile +4 -1
- data/Gemfile.lock +21 -3
- data/README.md +35 -39
- data/lib/take2.rb +67 -48
- data/lib/take2/backoff.rb +48 -0
- data/lib/take2/configuration.rb +35 -30
- data/lib/take2/version.rb +4 -2
- data/spec/spec_helper.rb +3 -1
- data/spec/take2/configuration_spec.rb +34 -63
- data/spec/take2_spec.rb +146 -152
- data/take2.gemspec +9 -7
- metadata +8 -6
data/lib/take2/configuration.rb
CHANGED
@@ -1,23 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'take2/backoff'
|
4
|
+
|
1
5
|
module Take2
|
2
6
|
class Configuration
|
3
|
-
CONFIG_ATTRS = [:retries,
|
7
|
+
CONFIG_ATTRS = [:retries,
|
8
|
+
:retriable,
|
9
|
+
:retry_proc,
|
10
|
+
:retry_condition_proc,
|
11
|
+
:backoff_intervals].freeze
|
12
|
+
|
4
13
|
attr_accessor(*CONFIG_ATTRS)
|
5
14
|
|
6
15
|
def initialize(options = {})
|
7
16
|
# Defaults
|
8
17
|
@retries = 3
|
9
|
-
@retriable = [
|
10
|
-
Net::HTTPServerError,
|
11
|
-
Net::HTTPServerException,
|
12
|
-
Net::HTTPRetriableError,
|
13
|
-
Errno::ECONNRESET,
|
14
|
-
IOError,
|
15
|
-
].freeze
|
18
|
+
@retriable = []
|
16
19
|
@retry_proc = proc {}
|
17
20
|
@retry_condition_proc = proc { false }
|
18
|
-
@
|
19
|
-
|
20
|
-
|
21
|
+
@backoff_intervals = Backoff.new(:constant, 3).intervals
|
22
|
+
|
23
|
+
merge_options!(options)
|
21
24
|
end
|
22
25
|
|
23
26
|
def to_hash
|
@@ -27,29 +30,31 @@ module Take2
|
|
27
30
|
end
|
28
31
|
|
29
32
|
def [](value)
|
30
|
-
|
33
|
+
public_send(value)
|
31
34
|
end
|
32
35
|
|
33
|
-
def
|
36
|
+
def merge_options!(options = {})
|
37
|
+
validate!(options).each do |key, value|
|
38
|
+
public_send("#{key}=", value)
|
39
|
+
end
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate!(options)
|
34
44
|
options.each do |k, v|
|
35
|
-
raise ArgumentError, "#{k} is not a valid configuration"
|
45
|
+
raise ArgumentError, "#{k} is not a valid configuration" unless CONFIG_ATTRS.include?(k)
|
36
46
|
case k
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
47
|
+
when :retries
|
48
|
+
raise ArgumentError, "#{k} must be positive integer" unless v.is_a?(Integer) && v.positive?
|
49
|
+
when :retriable
|
50
|
+
raise ArgumentError, "#{k} must be array of retriable errors" unless v.is_a?(Array)
|
51
|
+
when :backoff_intervals
|
52
|
+
raise ArgumentError, "#{k} must be array of retriable errors" unless v.is_a?(Array)
|
53
|
+
raise ArgumentError, "#{k} size must be greater or equal to number of retries" unless v.size >= retries
|
54
|
+
when :retry_proc, :retry_condition_proc
|
55
|
+
raise ArgumentError, "#{k} must be Proc" unless v.is_a?(Proc)
|
45
56
|
end
|
46
|
-
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def setter
|
51
|
-
proc { |key, value| instance_variable_set(:"@#{key}", value) }
|
57
|
+
end
|
52
58
|
end
|
53
|
-
|
54
59
|
end
|
55
|
-
end
|
60
|
+
end
|
data/lib/take2/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,125 +1,96 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'spec_helper'
|
4
4
|
|
5
|
+
RSpec.describe(Take2::Configuration) do
|
5
6
|
describe 'default configurations' do
|
6
|
-
|
7
7
|
let(:default) { described_class.new }
|
8
8
|
|
9
9
|
it 'has correct default value for retries' do
|
10
|
-
expect(default.retries).to
|
10
|
+
expect(default.retries).to(eql(3))
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'has correct default retriable errors array' do
|
14
|
-
expect(default.retriable).to
|
15
|
-
Net::HTTPServerError,
|
16
|
-
Net::HTTPServerException,
|
17
|
-
Net::HTTPRetriableError,
|
18
|
-
Errno::ECONNRESET,
|
19
|
-
IOError,
|
20
|
-
].freeze
|
14
|
+
expect(default.retriable).to(eql([]))
|
21
15
|
end
|
22
16
|
|
23
17
|
it 'has default proc for retry_proc' do
|
24
18
|
p = proc {}
|
25
|
-
expect(default.retry_proc.call).to
|
19
|
+
expect(default.retry_proc.call).to(eql(p.call))
|
26
20
|
end
|
27
21
|
|
28
22
|
it 'has default proc for retry_condition_proc' do
|
29
|
-
p = proc {false}
|
30
|
-
expect(default.retry_condition_proc.call).to
|
23
|
+
p = proc { false }
|
24
|
+
expect(default.retry_condition_proc.call).to(eql(p.call))
|
31
25
|
end
|
32
26
|
|
33
|
-
it 'has correct default value for
|
34
|
-
expect(default.
|
27
|
+
it 'has correct default value for backoff_intervals' do
|
28
|
+
expect(default.backoff_intervals).to eql Array.new(10, 3)
|
35
29
|
end
|
36
|
-
|
37
30
|
end
|
38
31
|
|
39
32
|
describe 'overwriting the default configurations' do
|
40
|
-
|
41
33
|
context 'with valid hash' do
|
42
|
-
|
43
|
-
let!(:new_configs_hash) {
|
34
|
+
let!(:new_configs_hash) do
|
44
35
|
{
|
45
36
|
retries: 2,
|
46
37
|
retriable: [Net::HTTPRetriableError],
|
47
38
|
retry_condition_proc: proc { true },
|
48
|
-
retry_proc: proc { 2*2 },
|
49
|
-
|
39
|
+
retry_proc: proc { 2 * 2 },
|
40
|
+
backoff_intervals: [1, 2, 3, 4, 5]
|
50
41
|
}
|
51
|
-
|
42
|
+
end
|
52
43
|
|
53
44
|
let!(:new_configuration) { described_class.new(new_configs_hash).to_hash }
|
54
45
|
|
55
|
-
[:retries, :retriable, :retry_proc, :retry_condition_proc, :
|
46
|
+
[:retries, :retriable, :retry_proc, :retry_condition_proc, :backoff_intervals].each do |key|
|
56
47
|
it "sets the #{key} key" do
|
57
48
|
if new_configs_hash[key].respond_to?(:call)
|
58
|
-
expect(new_configuration[key].call).to
|
59
|
-
else
|
60
|
-
expect(new_configuration[key]).to
|
49
|
+
expect(new_configuration[key].call).to(eql(new_configs_hash[key].call))
|
50
|
+
else
|
51
|
+
expect(new_configuration[key]).to(eql(new_configs_hash[key]))
|
61
52
|
end
|
62
53
|
end
|
63
54
|
end
|
64
|
-
|
65
55
|
end
|
66
56
|
|
67
57
|
context 'with invalid hash' do
|
68
|
-
|
69
58
|
context 'when retries set to invalid value' do
|
70
|
-
|
71
|
-
it 'raises ArgumentError' do
|
72
|
-
|
73
|
-
expect { described_class.new(retries: -1) }.to raise_error ArgumentError
|
74
|
-
expect { described_class.new(retries: 0) }.to raise_error ArgumentError
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
context 'when time_to_sleep set to invalid value' do
|
81
|
-
|
82
59
|
it 'raises ArgumentError' do
|
83
|
-
|
84
|
-
expect { described_class.new(
|
85
|
-
|
60
|
+
expect { described_class.new(retries: -1) }.to(raise_error(ArgumentError))
|
61
|
+
expect { described_class.new(retries: 0) }.to(raise_error(ArgumentError))
|
86
62
|
end
|
87
|
-
|
88
63
|
end
|
89
64
|
|
90
65
|
context 'when retriable set to invalid value' do
|
91
|
-
|
92
66
|
it 'raises ArgumentError' do
|
93
|
-
|
94
|
-
expect { described_class.new(retriable: StandardError) }.to raise_error ArgumentError
|
95
|
-
|
67
|
+
expect { described_class.new(retriable: StandardError) }.to(raise_error(ArgumentError))
|
96
68
|
end
|
97
|
-
|
98
69
|
end
|
99
70
|
|
100
71
|
context 'when retry_proc set to invalid value' do
|
101
|
-
|
102
72
|
it 'raises ArgumentError' do
|
103
|
-
|
104
|
-
expect { described_class.new(retry_proc: {}) }.to raise_error ArgumentError
|
105
|
-
|
73
|
+
expect { described_class.new(retry_proc: {}) }.to(raise_error(ArgumentError))
|
106
74
|
end
|
107
|
-
|
108
75
|
end
|
109
76
|
|
110
77
|
context 'when retry_condition_proc set to invalid value' do
|
111
|
-
|
112
78
|
it 'raises ArgumentError' do
|
79
|
+
expect { described_class.new(retry_condition_proc: {}) }.to(raise_error(ArgumentError))
|
80
|
+
end
|
81
|
+
end
|
113
82
|
|
114
|
-
|
115
|
-
|
83
|
+
context 'when backoff_intervals has incorrect type' do
|
84
|
+
it 'raises ArgumentError' do
|
85
|
+
expect { described_class.new(backoff_intervals: 1) }.to(raise_error(ArgumentError))
|
116
86
|
end
|
87
|
+
end
|
117
88
|
|
89
|
+
context 'when backoff_intervals size smaller then number of retries' do
|
90
|
+
it 'raises ArgumentError' do
|
91
|
+
expect { described_class.new(backoff_intervals: [1]) }.to(raise_error(ArgumentError))
|
92
|
+
end
|
118
93
|
end
|
119
|
-
|
120
94
|
end
|
121
|
-
|
122
95
|
end
|
123
|
-
|
124
|
-
|
125
|
-
end
|
96
|
+
end
|
data/spec/take2_spec.rb
CHANGED
@@ -1,162 +1,127 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'spec_helper'
|
4
4
|
|
5
|
+
RSpec.describe(Take2) do
|
5
6
|
let!(:config) do
|
6
7
|
Take2.configure do |c|
|
7
8
|
c.retries = 1
|
8
|
-
c.retriable = [
|
9
|
-
c.retry_condition_proc = proc {false}
|
9
|
+
c.retriable = [Errno::ECONNRESET, Net::HTTPRetriableError].freeze
|
10
|
+
c.retry_condition_proc = proc { false }
|
10
11
|
c.retry_proc = proc {}
|
11
|
-
c.
|
12
|
+
c.backoff_intervals = Take2::Backoff.new(:linear, 1).intervals
|
12
13
|
end
|
13
14
|
end
|
14
15
|
let(:klass) { Class.new { include Take2 } }
|
15
16
|
let(:object) { klass.new }
|
16
17
|
|
17
18
|
describe 'default values' do
|
18
|
-
|
19
19
|
subject { klass.retriable_configuration }
|
20
20
|
|
21
21
|
it 'has a default value for :retries' do
|
22
|
-
expect(subject[:retries]).to
|
22
|
+
expect(subject[:retries]).to(eql(described_class.configuration[:retries]))
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'has a default value for :retriable' do
|
26
|
-
expect(subject[:retriable]).to
|
26
|
+
expect(subject[:retriable]).to(eql(described_class.configuration[:retriable]))
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'has a default value for :retry_condition_proc' do
|
30
|
-
expect(subject[:retry_condition_proc].call).to
|
30
|
+
expect(subject[:retry_condition_proc].call).to(eql(described_class.configuration[:retry_condition_proc].call))
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'has a default value for :retry_proc' do
|
34
|
-
expect(subject[:retry_proc].call).to
|
34
|
+
expect(subject[:retry_proc].call).to(eql(described_class.configuration[:retry_proc].call))
|
35
35
|
end
|
36
36
|
|
37
|
-
it 'has a default value for :
|
38
|
-
expect(subject[:
|
37
|
+
it 'has a default value for :backoff_intervals' do
|
38
|
+
expect(subject[:backoff_intervals]).to eql((1..10).to_a)
|
39
39
|
end
|
40
|
-
|
41
40
|
end
|
42
41
|
|
43
42
|
describe 'included class helpers' do
|
44
|
-
|
45
43
|
subject { klass.retriable_configuration }
|
46
44
|
|
47
45
|
describe '.number_of_retries' do
|
48
|
-
|
49
46
|
context 'with valid argument' do
|
50
|
-
|
51
47
|
it 'sets the :retries attribute' do
|
52
|
-
klass.number_of_retries
|
53
|
-
expect(subject[:retries]).to
|
48
|
+
klass.number_of_retries(1)
|
49
|
+
expect(subject[:retries]).to(eql(1))
|
54
50
|
end
|
55
|
-
|
56
51
|
end
|
57
52
|
|
58
53
|
context 'with invalid argument' do
|
59
|
-
|
60
54
|
it 'raises ArgumentError' do
|
61
|
-
expect { klass.number_of_retries
|
55
|
+
expect { klass.number_of_retries(0) }.to(raise_error(ArgumentError))
|
62
56
|
end
|
63
|
-
|
64
57
|
end
|
65
|
-
|
66
58
|
end
|
67
59
|
|
68
60
|
describe '.retriable_errors' do
|
69
|
-
|
70
61
|
context 'with valid argument' do
|
71
|
-
|
72
62
|
it 'sets the :retriable_errors attribute' do
|
73
63
|
retriables = IOError
|
74
|
-
klass.retriable_errors
|
75
|
-
expect(subject[:retriable]).to
|
64
|
+
klass.retriable_errors(retriables)
|
65
|
+
expect(subject[:retriable]).to(eql([retriables]))
|
76
66
|
end
|
77
|
-
|
78
67
|
end
|
79
68
|
|
80
69
|
context 'with invalid argument' do
|
81
|
-
|
82
70
|
it 'raises ArgumentError' do
|
83
71
|
class Klass; end
|
84
|
-
expect { klass.retriable_errors
|
72
|
+
expect { klass.retriable_errors(Klass) }.to(raise_error(ArgumentError))
|
85
73
|
end
|
86
|
-
|
87
74
|
end
|
88
|
-
|
89
75
|
end
|
90
76
|
|
91
77
|
describe '.retriable_condition' do
|
92
|
-
|
93
78
|
context 'with valid argument' do
|
94
|
-
|
95
79
|
it 'sets the :retriable_condition attribute' do
|
96
80
|
retriable_proc = proc { 'Ho-Ho-Ho' }
|
97
|
-
klass.retriable_condition
|
98
|
-
expect(subject[:retry_condition_proc].call).to
|
81
|
+
klass.retriable_condition(retriable_proc)
|
82
|
+
expect(subject[:retry_condition_proc].call).to(eql(retriable_proc.call))
|
99
83
|
end
|
100
|
-
|
101
84
|
end
|
102
85
|
|
103
86
|
context 'with invalid argument' do
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
108
|
-
|
87
|
+
it 'raises ArgumentError' do
|
88
|
+
expect { klass.retriable_condition(Class.new) }.to(raise_error(ArgumentError))
|
89
|
+
end
|
109
90
|
end
|
110
|
-
|
111
91
|
end
|
112
92
|
|
113
93
|
describe '.on_retry' do
|
114
|
-
|
115
94
|
context 'with valid argument' do
|
116
|
-
|
117
95
|
it 'sets the :on_retry attribute' do
|
118
96
|
retry_proc = proc { |el| el }
|
119
|
-
klass.on_retry
|
120
|
-
expect(subject[:retry_proc].call).to
|
97
|
+
klass.on_retry(retry_proc)
|
98
|
+
expect(subject[:retry_proc].call).to(eql(retry_proc.call))
|
121
99
|
end
|
122
|
-
|
123
|
-
end
|
100
|
+
end
|
124
101
|
|
125
102
|
context 'with invalid argument' do
|
126
|
-
|
127
103
|
it 'raises ArgumentError' do
|
128
|
-
expect { klass.on_retry
|
104
|
+
expect { klass.on_retry(Class.new) }.to(raise_error(ArgumentError))
|
129
105
|
end
|
130
|
-
|
131
106
|
end
|
132
|
-
|
133
107
|
end
|
134
108
|
|
135
|
-
describe '.
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
klass.sleep_before_retry 3.5
|
141
|
-
expect(subject[:time_to_sleep]).to eql 3.5
|
109
|
+
describe '.backoff_setup' do
|
110
|
+
context 'with valid arguments' do
|
111
|
+
it 'sets the backoff_intervals' do
|
112
|
+
klass.backoff_strategy(type: :fibonacci, start: 3)
|
113
|
+
expect(subject[:backoff_intervals]).to eql([3, 5, 8, 13, 21, 34, 55, 89, 144, 233])
|
142
114
|
end
|
143
|
-
|
144
115
|
end
|
145
|
-
|
146
|
-
context 'with invalid argument' do
|
147
|
-
|
116
|
+
context 'with invalid backoff type' do
|
148
117
|
it 'raises ArgumentError' do
|
149
|
-
expect { klass.
|
118
|
+
expect { klass.backoff_strategy(type: :not_real, start: 3) }.to(raise_error(ArgumentError))
|
150
119
|
end
|
151
|
-
|
152
120
|
end
|
153
|
-
|
154
121
|
end
|
155
|
-
|
156
122
|
end
|
157
123
|
|
158
124
|
describe '.call_api_with_retry' do
|
159
|
-
|
160
125
|
def increment_retry_counter
|
161
126
|
@tries += 1
|
162
127
|
end
|
@@ -166,115 +131,144 @@ RSpec.describe Take2 do
|
|
166
131
|
raise error
|
167
132
|
end
|
168
133
|
|
169
|
-
|
170
|
-
|
171
|
-
let(:error) { StandardError.new 'Release the Kraken!!' }
|
172
|
-
|
134
|
+
describe 'class method' do
|
135
|
+
let(:retriable_error) { Net::HTTPRetriableError.new('Release the Kraken...many times!!', nil) }
|
173
136
|
before(:each) { @tries = 0 }
|
174
137
|
|
175
|
-
it '
|
176
|
-
expect
|
177
|
-
|
178
|
-
|
138
|
+
it 'responds to the method' do
|
139
|
+
expect(klass).to respond_to(:call_api_with_retry)
|
140
|
+
expect(klass).to respond_to(:with_retry)
|
141
|
+
expect(klass.method(:with_retry).original_name).to eq(klass.method(:call_api_with_retry).original_name)
|
142
|
+
expect(klass.method(:with_retry).source_location).to eq(klass.method(:call_api_with_retry).source_location)
|
179
143
|
end
|
180
144
|
|
181
|
-
it '
|
145
|
+
it 'retries correct number of times' do
|
182
146
|
expect do
|
183
|
-
|
184
|
-
end.to
|
147
|
+
klass.call_api_with_retry { wrath_the_gods_with retriable_error }
|
148
|
+
end.to(change { @tries }.from(0).to(klass.retriable_configuration[:retries] + 1))
|
149
|
+
rescue
|
150
|
+
nil
|
185
151
|
end
|
186
|
-
|
187
|
-
# it 'logs the error' do
|
188
|
-
# expect(object).to receive(:log_error).with(error)
|
189
|
-
# object.call_api_with_retry { wrath_the_gods_with error } rescue nil
|
190
|
-
# end
|
191
|
-
|
192
152
|
end
|
193
153
|
|
194
|
-
|
154
|
+
describe 'instance method' do
|
155
|
+
it 'responds to the method' do
|
156
|
+
expect(object).to respond_to(:call_api_with_retry)
|
157
|
+
expect(object).to respond_to(:with_retry)
|
158
|
+
expect(object.method(:with_retry).original_name).to eq(object.method(:call_api_with_retry).original_name)
|
159
|
+
expect(object.method(:with_retry).source_location).to eq(object.method(:call_api_with_retry).source_location)
|
160
|
+
end
|
195
161
|
|
196
|
-
|
162
|
+
context 'when raised with non retriable error' do
|
163
|
+
let(:error) { StandardError.new('Release the Kraken!!') }
|
197
164
|
|
198
|
-
|
165
|
+
before(:each) { @tries = 0 }
|
199
166
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
167
|
+
it 're raises the original error' do
|
168
|
+
expect do
|
169
|
+
object.call_api_with_retry { wrath_the_gods_with error }
|
170
|
+
end.to(raise_error(error.class))
|
171
|
+
end
|
205
172
|
|
206
|
-
|
207
|
-
|
208
|
-
|
173
|
+
it 'is not retried' do
|
174
|
+
expect do
|
175
|
+
object.call_api_with_retry { wrath_the_gods_with error }
|
176
|
+
end.to(change { @tries }.from(0).to(1))
|
177
|
+
rescue
|
178
|
+
nil
|
179
|
+
end
|
209
180
|
end
|
210
181
|
|
211
|
-
|
212
|
-
|
213
|
-
object.call_api_with_retry { wrath_the_gods_with retriable_error } rescue nil
|
214
|
-
end
|
182
|
+
context 'when raised with retriable error' do
|
183
|
+
let(:retriable_error) { Net::HTTPRetriableError.new('Release the Kraken...many times!!', nil) }
|
215
184
|
|
216
|
-
|
217
|
-
allow_any_instance_of(Object).to receive(:sleep).with(klass.retriable_configuration[:time_to_sleep])
|
218
|
-
object.call_api_with_retry { wrath_the_gods_with retriable_error } rescue nil
|
219
|
-
end
|
185
|
+
before(:each) { @tries = 0 }
|
220
186
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
187
|
+
it 'retries correct number of times' do
|
188
|
+
expect do
|
189
|
+
object.call_api_with_retry { wrath_the_gods_with retriable_error }
|
190
|
+
end.to(change { @tries }.from(0).to(klass.retriable_configuration[:retries] + 1))
|
191
|
+
rescue
|
192
|
+
nil
|
193
|
+
end
|
225
194
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
195
|
+
it 'calls the retry proc' do
|
196
|
+
expect(klass.retriable_configuration[:retry_proc])
|
197
|
+
.to(receive(:call)
|
198
|
+
.exactly(klass.retriable_configuration[:retries]))
|
199
|
+
begin
|
200
|
+
object.call_api_with_retry { wrath_the_gods_with retriable_error }
|
201
|
+
rescue
|
202
|
+
nil
|
203
|
+
end
|
204
|
+
end
|
231
205
|
|
232
|
-
|
206
|
+
it 'calls the retry_condition proc' do
|
207
|
+
expect(klass.retriable_configuration[:retry_condition_proc])
|
208
|
+
.to(receive(:call)
|
209
|
+
.exactly(klass.retriable_configuration[:retries]))
|
210
|
+
begin
|
211
|
+
object.call_api_with_retry { wrath_the_gods_with retriable_error }
|
212
|
+
rescue
|
213
|
+
nil
|
214
|
+
end
|
215
|
+
end
|
233
216
|
|
234
|
-
|
217
|
+
it 're raises the original error' do
|
218
|
+
expect do
|
219
|
+
object.call_api_with_retry { wrath_the_gods_with retriable_error }
|
220
|
+
end.to(raise_error(retriable_error.class))
|
221
|
+
end
|
222
|
+
end
|
235
223
|
|
236
|
-
|
237
|
-
|
224
|
+
context 'with custom options' do
|
225
|
+
let(:retriable_error) { Net::HTTPRetriableError.new('Release the Kraken...many times!!', nil) }
|
226
|
+
let(:new_retriable_error) { IOError.new('You shall not PASS!') }
|
238
227
|
|
239
|
-
|
240
|
-
|
241
|
-
it 'overwrites the :retries' do
|
242
|
-
expect do
|
243
|
-
object.call_api_with_retry(retries: 3) { wrath_the_gods_with retriable_error } rescue nil
|
244
|
-
end.to change { @tries }.from(0).to(4)
|
245
|
-
end
|
228
|
+
before(:each) { @tries = 0 }
|
246
229
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
230
|
+
it 'overwrites the :retries' do
|
231
|
+
expect do
|
232
|
+
object.call_api_with_retry(retries: 3) { wrath_the_gods_with retriable_error }
|
233
|
+
end.to(change { @tries }.from(0).to(4))
|
234
|
+
rescue
|
235
|
+
nil
|
236
|
+
end
|
252
237
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
238
|
+
it 'overwrites the :retry_proc' do
|
239
|
+
new_proc = proc { 1**1 }
|
240
|
+
expect(new_proc).to(receive(:call).exactly(klass.retriable_configuration[:retries]))
|
241
|
+
begin
|
242
|
+
object.call_api_with_retry(retry_proc: new_proc) { wrath_the_gods_with retriable_error }
|
243
|
+
rescue
|
244
|
+
nil
|
245
|
+
end
|
246
|
+
end
|
258
247
|
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
248
|
+
it 'overwrites the :retry_condition_proc' do
|
249
|
+
new_proc = proc { true }
|
250
|
+
expect(new_proc).to(receive(:call).exactly(klass.retriable_configuration[:retries]))
|
251
|
+
begin
|
252
|
+
object.call_api_with_retry(retry_condition_proc: new_proc) { wrath_the_gods_with retriable_error }
|
253
|
+
rescue
|
254
|
+
nil
|
255
|
+
end
|
256
|
+
end
|
263
257
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
258
|
+
it 'overwrites the :retriable' do
|
259
|
+
expect do
|
260
|
+
object.call_api_with_retry(retriable: [new_retriable_error]) { wrath_the_gods_with retriable_error }
|
261
|
+
end.to(change { @tries }.from(0).to(1))
|
262
|
+
rescue
|
263
|
+
nil
|
264
|
+
end
|
269
265
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
266
|
+
it 'raises ArgumentError if there are invalid keys' do
|
267
|
+
expect do
|
268
|
+
object.call_api_with_retry(invalid_key: :nope) { wrath_the_gods_with retriable_error }
|
269
|
+
end.to(raise_error(ArgumentError))
|
270
|
+
end
|
274
271
|
end
|
275
|
-
|
276
272
|
end
|
277
|
-
|
278
273
|
end
|
279
|
-
|
280
|
-
end
|
274
|
+
end
|