retriable 3.4.1 → 4.2.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 +4 -4
- data/.github/workflows/main.yml +43 -11
- data/.hound.yml +1 -1
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +118 -0
- data/Gemfile +4 -1
- data/README.md +214 -95
- data/docs/testing.md +212 -0
- data/lib/retriable/config.rb +81 -10
- data/lib/retriable/core_ext/kernel.rb +6 -4
- data/lib/retriable/exponential_backoff.rb +44 -10
- data/lib/retriable/validation.rb +95 -0
- data/lib/retriable/version.rb +1 -1
- data/lib/retriable.rb +185 -42
- data/retriable.gemspec +2 -7
- data/sig/retriable.rbs +29 -1
- data/spec/config_spec.rb +157 -4
- data/spec/exponential_backoff_spec.rb +45 -26
- data/spec/retriable_spec.rb +915 -6
- data/spec/spec_helper.rb +3 -1
- metadata +9 -53
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a551efb6db5acea9e82dde8e48afdea1869f6b93461a3c48c33f8385fbea6392
|
|
4
|
+
data.tar.gz: fbf6bb8c5ade48420e0f2a43532bafff0e4159eb4cf149bce559116ec1c91e50
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 19d5ac72e1614b7fdb3984697db76ad3f6ae2e9b1f60ff1eb470e210738cd67154afc2776b55329fca345fad6263035a41eb0748626f427fd2d05cc0bfea9c89
|
|
7
|
+
data.tar.gz: c1d46594742b7c19985a63037199125b718e6c6395dd8276013719d8c7f9cd64376637471b90fa9249869767da9a2474cafc31afd04f373f73249d8ebdfa0337
|
data/.github/workflows/main.yml
CHANGED
|
@@ -7,37 +7,36 @@ on:
|
|
|
7
7
|
branches: [main]
|
|
8
8
|
types: [opened, synchronize, reopened]
|
|
9
9
|
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
10
13
|
jobs:
|
|
11
14
|
ci:
|
|
12
15
|
# The type of runner that the job will run on
|
|
13
16
|
runs-on: ${{ matrix.os }}
|
|
17
|
+
# Ruby 4.0 is still in preview. Treat its results as informational so a
|
|
18
|
+
# preview-only regression doesn't block merges. Drop this gate (or update
|
|
19
|
+
# the version literal) once Ruby 4.0 is released and we treat it as
|
|
20
|
+
# required.
|
|
21
|
+
continue-on-error: ${{ matrix.ruby == '4.0' }}
|
|
14
22
|
strategy:
|
|
15
23
|
matrix:
|
|
16
24
|
os: [ubuntu-24.04]
|
|
17
25
|
ruby:
|
|
18
26
|
[
|
|
19
|
-
"2.3",
|
|
20
|
-
"2.4",
|
|
21
|
-
"2.5",
|
|
22
|
-
"2.6",
|
|
23
|
-
"2.7",
|
|
24
|
-
"3.0",
|
|
25
|
-
"3.1",
|
|
26
27
|
"3.2",
|
|
27
28
|
"3.3",
|
|
28
29
|
"3.4",
|
|
29
30
|
"4.0",
|
|
30
31
|
jruby,
|
|
31
32
|
]
|
|
32
|
-
env:
|
|
33
|
-
CC_TEST_REPORTER_ID: 20a1139ef1830b4f813a10a03d90e8aa179b5226f75e75c5a949b25756ebf558
|
|
34
33
|
|
|
35
34
|
steps:
|
|
36
35
|
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
|
37
|
-
- uses: actions/checkout@v6
|
|
36
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
38
37
|
|
|
39
38
|
- name: Setup ruby
|
|
40
|
-
uses: ruby/setup-ruby@v1
|
|
39
|
+
uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1
|
|
41
40
|
with:
|
|
42
41
|
ruby-version: ${{ matrix.ruby }}
|
|
43
42
|
bundler-cache: true
|
|
@@ -47,3 +46,36 @@ jobs:
|
|
|
47
46
|
|
|
48
47
|
- name: Run rspec
|
|
49
48
|
run: bundle exec rspec
|
|
49
|
+
|
|
50
|
+
lint:
|
|
51
|
+
runs-on: ubuntu-24.04
|
|
52
|
+
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
55
|
+
|
|
56
|
+
- name: Setup ruby
|
|
57
|
+
uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1
|
|
58
|
+
with:
|
|
59
|
+
ruby-version: "3.3"
|
|
60
|
+
bundler-cache: true
|
|
61
|
+
|
|
62
|
+
- name: Run rubocop
|
|
63
|
+
run: bundle exec rubocop
|
|
64
|
+
|
|
65
|
+
- name: Validate RBS
|
|
66
|
+
run: bundle exec rbs -I sig validate
|
|
67
|
+
|
|
68
|
+
audit:
|
|
69
|
+
runs-on: ubuntu-24.04
|
|
70
|
+
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
73
|
+
|
|
74
|
+
- name: Setup ruby
|
|
75
|
+
uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1
|
|
76
|
+
with:
|
|
77
|
+
ruby-version: "3.3"
|
|
78
|
+
bundler-cache: true
|
|
79
|
+
|
|
80
|
+
- name: Run bundler-audit
|
|
81
|
+
run: bundle exec bundle-audit check --update
|
data/.hound.yml
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
ruby:
|
|
2
|
-
|
|
2
|
+
enabled: false
|
data/.rubocop.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
AllCops:
|
|
2
2
|
NewCops: enable
|
|
3
|
-
TargetRubyVersion: 2
|
|
3
|
+
TargetRubyVersion: 3.2
|
|
4
4
|
|
|
5
5
|
Style/StringLiterals:
|
|
6
6
|
EnforcedStyle: double_quotes
|
|
@@ -40,3 +40,6 @@ Metrics/AbcSize:
|
|
|
40
40
|
|
|
41
41
|
Style/TrailingCommaInArrayLiteral:
|
|
42
42
|
Enabled: false
|
|
43
|
+
|
|
44
|
+
Naming/MethodParameterName:
|
|
45
|
+
MinNameLength: 2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,123 @@
|
|
|
1
1
|
# HEAD
|
|
2
2
|
|
|
3
|
+
## 4.2.0
|
|
4
|
+
|
|
5
|
+
### Bug fixes
|
|
6
|
+
|
|
7
|
+
- The `Kernel` extension methods (`require "retriable/core_ext/kernel"`) are now
|
|
8
|
+
private, matching idiomatic `Kernel` helpers like `puts` and `rand`.
|
|
9
|
+
Previously `retriable` and `retriable_with_context` were public instance
|
|
10
|
+
methods, so they leaked onto every object's public API and could be invoked
|
|
11
|
+
with an explicit receiver (e.g. `"foo".retriable { ... }`). They remain
|
|
12
|
+
callable in the documented receiver-less form.
|
|
13
|
+
([#146](https://github.com/kamui/retriable/pull/146))
|
|
14
|
+
- `Retriable.with_context` (and `Kernel#retriable_with_context`) now raises
|
|
15
|
+
`ArgumentError` when called without a block, matching `with_override`.
|
|
16
|
+
Previously a missing block was silently ignored: the call returned `nil` and
|
|
17
|
+
the intended block never ran, hiding a caller bug. Behavior change: code that
|
|
18
|
+
relied on the silent no-op will now raise.
|
|
19
|
+
- `Config#validate!` now validates the structure of each entry in `contexts`,
|
|
20
|
+
so configured contexts are checked on every `Retriable.retriable`/
|
|
21
|
+
`with_context` call rather than only when a given context is first used. A
|
|
22
|
+
context whose options contain an unknown key (including a nested `contexts`
|
|
23
|
+
key) now raises `ArgumentError, "<key> is not a valid option"`, matching the
|
|
24
|
+
`with_override` path. Non-Hash `contexts` and non-Hash per-context values
|
|
25
|
+
remain leniently treated as empty options (no behavior change). Option
|
|
26
|
+
_values_ are still validated lazily at retry time, unchanged.
|
|
27
|
+
|
|
28
|
+
### Docs
|
|
29
|
+
|
|
30
|
+
- Document that `on_retry` receives `next_interval: nil` on the final rescued
|
|
31
|
+
attempt, when Retriable is about to give up because `tries` are exhausted.
|
|
32
|
+
`on_retry` still fires before `on_give_up` (unchanged behavior); the `nil`
|
|
33
|
+
contract is now called out in the `on_retry` documentation so handlers guard
|
|
34
|
+
arithmetic or logging on `next_interval`.
|
|
35
|
+
|
|
36
|
+
### Performance
|
|
37
|
+
|
|
38
|
+
- `Config#initialize` no longer allocates a throwaway `ExponentialBackoff` (and
|
|
39
|
+
runs its redundant `validate!`) just to read default values. Defaults now live
|
|
40
|
+
in a frozen `ExponentialBackoff::DEFAULTS` constant, removing an allocation and
|
|
41
|
+
redundant validation from the `retriable` hot path.
|
|
42
|
+
([#149](https://github.com/kamui/retriable/pull/149))
|
|
43
|
+
|
|
44
|
+
## 4.1.1
|
|
45
|
+
|
|
46
|
+
### Bug fixes
|
|
47
|
+
|
|
48
|
+
- `retry_if`, `on_retry`, and `on_give_up` are now validated to be callable
|
|
49
|
+
(respond to `#call`) or falsy. A non-callable truthy value raises
|
|
50
|
+
`ArgumentError` at configuration time instead of a later `NoMethodError` on a
|
|
51
|
+
retry path. ([#140](https://github.com/kamui/retriable/pull/140))
|
|
52
|
+
|
|
53
|
+
### Internal
|
|
54
|
+
|
|
55
|
+
- Add RBS type signatures for the public API (`Retriable.configure`, `config`,
|
|
56
|
+
`retriable`, `with_override`, `with_context`, and `Retriable::Config`) and
|
|
57
|
+
validate them in CI with `rbs validate`.
|
|
58
|
+
([#142](https://github.com/kamui/retriable/pull/142))
|
|
59
|
+
- Enforce a minimum test coverage floor and add a `bundler-audit` dependency
|
|
60
|
+
audit job to CI. ([#143](https://github.com/kamui/retriable/pull/143))
|
|
61
|
+
- Remove an unused `CC_TEST_REPORTER_ID` from the CI workflow.
|
|
62
|
+
([#141](https://github.com/kamui/retriable/pull/141))
|
|
63
|
+
|
|
64
|
+
## 4.1.0
|
|
65
|
+
|
|
66
|
+
### Bug fixes
|
|
67
|
+
|
|
68
|
+
- A per-call or `with_context` `tries:` now clears an inherited `intervals:` from
|
|
69
|
+
global config or a context, matching the documented precedence. Previously
|
|
70
|
+
`Retriable.retriable(tries: 1)` was silently ignored when `intervals` was
|
|
71
|
+
configured, running `intervals.size + 1` times. Passing both `intervals:` and
|
|
72
|
+
`tries:` in the same call still lets `intervals:` win.
|
|
73
|
+
|
|
74
|
+
## 4.0.0
|
|
75
|
+
|
|
76
|
+
**This is a major release with breaking changes. Please read carefully before upgrading.**
|
|
77
|
+
|
|
78
|
+
### Breaking changes
|
|
79
|
+
|
|
80
|
+
- Removed `timeout:` option. The `timeout:` option has been removed from `Retriable.retriable`, `Retriable.configure`, and `Retriable.with_override`. It was a thin wrapper around Ruby's `Timeout.timeout`, which has well-documented safety issues: it interrupts execution at arbitrary lines and can corrupt internal state in libraries that are not interrupt-safe (mutexes, file handles, network sockets, allocator state). This was first raised against this gem in [#96](https://github.com/kamui/retriable/issues/96) in 2021; Retriable 3.8.0 deprecated the option, and 4.0 removes the footgun entirely. As a side effect, the historical bug where Retriable's own internal `Timeout::Error` was silently retried by default is no longer reachable, since Retriable no longer raises a timeout itself. User-raised `Timeout::Error` (for example, from a `Timeout.timeout` block you write inside the retried block) is still matched by the default `on: [StandardError]` because `Timeout::Error < RuntimeError < StandardError`. Passing `timeout:` to `Retriable.retriable` or `Retriable.with_override` now raises `ArgumentError`; setting `config.timeout` in `Retriable.configure` now raises `NoMethodError` because the configuration attribute has been removed. See the [4.0 migration section in the README](README.md#migration-from-3x-to-40) for replacement patterns.
|
|
81
|
+
- Minimum Ruby version is now 3.2. Support for Ruby 2.x, 3.0, and 3.1 has been dropped in Retriable 4.0. If you need Retriable on Ruby 2.3.0-3.1.x, the 3.8.x line (`~> 3.8`) remains available.
|
|
82
|
+
|
|
83
|
+
### Features
|
|
84
|
+
|
|
85
|
+
- Add [`on_give_up`](README.md#callbacks) callback that runs when Retriable stops retrying after a rescued retriable exception. Receives `(exception, try, elapsed_time, next_interval, reason)`, where `reason` is `:tries_exhausted` or `:max_elapsed_time`. Does not fire for non-retriable exceptions or `retry_if` rejections. Pass `on_give_up: false` to suppress a configured handler for a single call.
|
|
86
|
+
- Accept a [`Set` of `Exception` classes](README.md#configuring-which-options-to-retry-with-on) as the `on:` option, in addition to a single class, an `Array`, or a `Hash`.
|
|
87
|
+
|
|
88
|
+
### Internal
|
|
89
|
+
|
|
90
|
+
- Switched `Retriable.retriable`, `Retriable.with_context`, and the `Kernel` extension methods to Ruby 3.1+ anonymous block forwarding. No user-visible behavior change.
|
|
91
|
+
|
|
92
|
+
## 3.8.0
|
|
93
|
+
|
|
94
|
+
### Deprecations
|
|
95
|
+
|
|
96
|
+
- Deprecated the `timeout:` option ahead of its removal in Retriable 4.0. Non-nil timeout values supplied through `Retriable.configure`, `Retriable.retriable(...)`, or `Retriable.with_override(...)` now emit a deprecation warning while keeping the existing runtime behavior unchanged. On Ruby 2.7+ the warning is emitted via `Kernel.warn(..., category: :deprecated)`, so callers can silence it through the standard Ruby controls (`Warning[:deprecated] = false`, `ruby -W:no-deprecated`, or a custom `Warning.warn`). To keep the notice from drowning busy applications, it is emitted at most once per process; suppression via `Warning[:deprecated]` leaves the warner armed for the next call that re-enables the category. Prefer library-native timeout settings, or wrap the retried block in `Timeout.timeout(...)` directly if you still need that behavior. See the README migration guidance for details.
|
|
97
|
+
|
|
98
|
+
## 3.7.0
|
|
99
|
+
|
|
100
|
+
- Feature: Opt-in unbounded retries via `tries: Float::INFINITY`. Requires a finite `max_elapsed_time` as a safety bound and is incompatible with custom `intervals:`. Both invalid configurations raise `ArgumentError` from `Config#validate!`.
|
|
101
|
+
|
|
102
|
+
## 3.6.1
|
|
103
|
+
|
|
104
|
+
- Fix: Validate the `on:` option before retrying. Previously, passing a non-`Exception` value such as `Object`, `Kernel`, or a plain `Module` (which appear in every `Exception`'s ancestor chain) would silently retry process-critical exceptions like `SystemExit` and `Interrupt`. The `on:` option now requires an `Exception` subclass, an array of them, or a hash whose keys are such classes and whose values are `nil`, a `Regexp`, or an array of `Regexp`s. Invalid shapes raise `ArgumentError` before the block runs.
|
|
105
|
+
- Fix: Validate `with_override(contexts:)` shape before applying overrides. `contexts` may be `nil` or a hash, and each per-context override must be a hash.
|
|
106
|
+
- Docs: Document that `on_retry: false` disables a callback set in `Retriable.configure` for a single call.
|
|
107
|
+
|
|
108
|
+
## 3.6.0
|
|
109
|
+
|
|
110
|
+
- Breaking: `Retriable.override` and `Retriable.reset_override` are removed and replaced by block-scoped `Retriable.with_override(opts) { ... }`. The new API requires a block, restores the previous override (or absence of override) when the block exits via `ensure`, and is thread-local — overrides set in one thread do not affect other threads, and child threads do not inherit them. Fibers within a thread still share the thread's active override. Nested `with_override` calls correctly restore the outer override on inner exit. See the README and `docs/testing.md` for migration and testing patterns. This replaces the override API introduced in 3.5.0.
|
|
111
|
+
|
|
112
|
+
## 3.5.1
|
|
113
|
+
|
|
114
|
+
- Fix: Validate retry timing and count options before use to reject invalid retry configurations. `tries` must now be a positive integer unless a custom `intervals` array is provided.
|
|
115
|
+
|
|
116
|
+
## 3.5.0
|
|
117
|
+
|
|
118
|
+
- Fix: Do not count skipped sleep intervals against `max_elapsed_time` when `sleep_disabled` is true.
|
|
119
|
+
- Add `override` and `reset_override` APIs to force retry settings over local call options when needed (for example, test short-circuiting).
|
|
120
|
+
|
|
3
121
|
## 3.4.1
|
|
4
122
|
|
|
5
123
|
- Fix: Use `Process.clock_gettime(CLOCK_MONOTONIC)` for elapsed time tracking so retry timing is immune to wall-clock adjustments (NTP, manual changes).
|
data/Gemfile
CHANGED