retriable 3.4.0 → 3.4.1
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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +1 -1
- data/lib/retriable/exponential_backoff.rb +2 -2
- data/lib/retriable/version.rb +1 -1
- data/lib/retriable.rb +6 -3
- data/spec/retriable_spec.rb +32 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 86086d1d868b9f609e96d2b5e8e5f6e5910a9822b7c21dd86a4014a12105d7f3
|
|
4
|
+
data.tar.gz: a7324a228f6b0565428cb10afe6ecf3a98b7a6984ced4f83c32595f97767b09b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fc0f71e125a40e52fdb8e4cb99b71b066fc84a067e9011b166a14d08a9f98f20a15a32402818705172275ea8b0a0f814963265eabba9fcae6d7ac40cdfc9e520
|
|
7
|
+
data.tar.gz: d13f82d53fdc1c2be693a056fd4d164cddc4a7b34096c6c7367213f899881687854a3df5a20a07ad3678c3aa257297bd42a68cb36e9cf0718a2fa8be54a3bd56
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# HEAD
|
|
2
2
|
|
|
3
|
+
## 3.4.1
|
|
4
|
+
|
|
5
|
+
- Fix: Use `Process.clock_gettime(CLOCK_MONOTONIC)` for elapsed time tracking so retry timing is immune to wall-clock adjustments (NTP, manual changes).
|
|
6
|
+
- Fix: Handle `max_elapsed_time: nil` gracefully instead of raising `NoMethodError`.
|
|
7
|
+
- Remove dead `* 1.0` float coercion in `ExponentialBackoff#randomize`.
|
|
8
|
+
|
|
3
9
|
## 3.4.0
|
|
4
10
|
|
|
5
11
|
- Add `retry_if` option to support custom retry predicates, including checks against wrapped `exception.cause` values.
|
data/README.md
CHANGED
|
@@ -87,7 +87,7 @@ Here are the available options, in some vague order of relevance to most common
|
|
|
87
87
|
| **`on_retry`** | `nil` | `Proc` to call after each try is rescued. [Read more](#callbacks). |
|
|
88
88
|
| **`sleep_disabled`** | `false` | When true, disable exponential backoff and attempt retries immediately. |
|
|
89
89
|
| **`base_interval`** | `0.5` | The initial interval in seconds between tries. |
|
|
90
|
-
| **`max_elapsed_time`** | `900` (15 min) | The maximum amount of total time in seconds that code is allowed to keep being retried.
|
|
90
|
+
| **`max_elapsed_time`** | `900` (15 min) | The maximum amount of total time in seconds that code is allowed to keep being retried. Set to `nil` to disable the time limit and retry based solely on `tries`. |
|
|
91
91
|
| **`max_interval`** | `60` | The maximum interval in seconds that any individual retry can reach. |
|
|
92
92
|
| **`multiplier`** | `1.5` | Each successive interval grows by this factor. A multipler of 1.5 means the next interval will be 1.5x the current interval. |
|
|
93
93
|
| **`rand_factor`** | `0.5` | The percentage to randomize the next retry interval time. The next interval calculation is `randomized_interval = retry_interval * (random value in range [1 - randomization_factor, 1 + randomization_factor])` |
|
|
@@ -28,7 +28,7 @@ module Retriable
|
|
|
28
28
|
|
|
29
29
|
def intervals
|
|
30
30
|
intervals = Array.new(tries) do |iteration|
|
|
31
|
-
[base_interval * multiplier**iteration, max_interval].min
|
|
31
|
+
[base_interval * (multiplier**iteration), max_interval].min
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
return intervals if rand_factor.zero?
|
|
@@ -39,7 +39,7 @@ module Retriable
|
|
|
39
39
|
private
|
|
40
40
|
|
|
41
41
|
def randomize(interval)
|
|
42
|
-
delta = rand_factor * interval
|
|
42
|
+
delta = rand_factor * interval.to_f
|
|
43
43
|
min = interval - delta
|
|
44
44
|
max = interval + delta
|
|
45
45
|
rand(min..max)
|
data/lib/retriable/version.rb
CHANGED
data/lib/retriable.rb
CHANGED
|
@@ -41,8 +41,8 @@ module Retriable
|
|
|
41
41
|
|
|
42
42
|
exception_list = on.is_a?(Hash) ? on.keys : on
|
|
43
43
|
exception_list = [*exception_list]
|
|
44
|
-
start_time =
|
|
45
|
-
elapsed_time = -> {
|
|
44
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
45
|
+
elapsed_time = -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time }
|
|
46
46
|
|
|
47
47
|
tries = intervals.size + 1
|
|
48
48
|
|
|
@@ -101,7 +101,10 @@ module Retriable
|
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
def can_retry?(try, tries, elapsed_time, interval, max_elapsed_time)
|
|
104
|
-
try < tries
|
|
104
|
+
return false unless try < tries
|
|
105
|
+
return true if max_elapsed_time.nil?
|
|
106
|
+
|
|
107
|
+
(elapsed_time + interval) <= max_elapsed_time
|
|
105
108
|
end
|
|
106
109
|
|
|
107
110
|
# When `on` is a Hash, we need to verify the exception matches a pattern.
|
data/spec/retriable_spec.rb
CHANGED
|
@@ -315,6 +315,38 @@ describe Retriable do
|
|
|
315
315
|
expect(@tries).to eq(2)
|
|
316
316
|
end
|
|
317
317
|
|
|
318
|
+
it "retries up to tries limit when max_elapsed_time is nil" do
|
|
319
|
+
expect do
|
|
320
|
+
described_class.retriable(tries: 4, max_elapsed_time: nil) { increment_tries_with_exception }
|
|
321
|
+
end.to raise_error(StandardError)
|
|
322
|
+
|
|
323
|
+
expect(@tries).to eq(4)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
it "uses monotonic clock for elapsed time tracking" do
|
|
327
|
+
# Stub Process.clock_gettime to return controlled values so we can
|
|
328
|
+
# verify elapsed_time passed to on_retry is derived from the monotonic clock.
|
|
329
|
+
clock_calls = 0
|
|
330
|
+
allow(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC) do
|
|
331
|
+
value = clock_calls.to_f
|
|
332
|
+
clock_calls += 1
|
|
333
|
+
value
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
elapsed_times = []
|
|
337
|
+
on_retry = ->(_exception, _try, elapsed_time, _next_interval) { elapsed_times << elapsed_time }
|
|
338
|
+
|
|
339
|
+
expect do
|
|
340
|
+
described_class.retriable(tries: 3, on_retry: on_retry) { increment_tries_with_exception }
|
|
341
|
+
end.to raise_error(StandardError)
|
|
342
|
+
|
|
343
|
+
# start_time (call 0) + at least one elapsed_time computation per retry
|
|
344
|
+
expect(clock_calls).to be >= 3
|
|
345
|
+
# elapsed_time values should be positive and non-decreasing
|
|
346
|
+
expect(elapsed_times).to all(be > 0)
|
|
347
|
+
expect(elapsed_times).to eq(elapsed_times.sort)
|
|
348
|
+
end
|
|
349
|
+
|
|
318
350
|
it "raises ArgumentError on invalid options" do
|
|
319
351
|
expect { described_class.retriable(does_not_exist: 123) { increment_tries } }.to raise_error(ArgumentError)
|
|
320
352
|
end
|