retriable 3.1.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b43ddaf802607e93a68f1f2862c4a951b10f98ff3447f70da26ca72582f5c2ec
4
- data.tar.gz: 6893753a86f08975dd6781ce504ef5e373c3ce06ccc56e1fabbb46a701893bfb
3
+ metadata.gz: 86086d1d868b9f609e96d2b5e8e5f6e5910a9822b7c21dd86a4014a12105d7f3
4
+ data.tar.gz: a7324a228f6b0565428cb10afe6ecf3a98b7a6984ced4f83c32595f97767b09b
5
5
  SHA512:
6
- metadata.gz: 67c9f7740db524df4f4b5301c9c66fbecfc70a98413d4e2dc830f19ecc8365d507373f481a678e53c4ca23063069319d2198bac4f89e6a9641b7c6e0487928f8
7
- data.tar.gz: 76f62f0a03ac6e7c43c5fd6e6eeaaa3223edae83e55414bff6ec24464ab1991e6c405e569a7c17cfe0b3904bcec52867e69d9743440e14fb0a7d56ab7ff080fd
6
+ metadata.gz: fc0f71e125a40e52fdb8e4cb99b71b066fc84a067e9011b166a14d08a9f98f20a15a32402818705172275ea8b0a0f814963265eabba9fcae6d7ac40cdfc9e520
7
+ data.tar.gz: d13f82d53fdc1c2be693a056fd4d164cddc4a7b34096c6c7367213f899881687854a3df5a20a07ad3678c3aa257297bd42a68cb36e9cf0718a2fa8be54a3bd56
@@ -0,0 +1,8 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "10:00"
8
+ open-pull-requests-limit: 10
@@ -0,0 +1,49 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ types: [opened, synchronize, reopened]
9
+
10
+ jobs:
11
+ ci:
12
+ # The type of runner that the job will run on
13
+ runs-on: ${{ matrix.os }}
14
+ strategy:
15
+ matrix:
16
+ os: [ubuntu-24.04]
17
+ ruby:
18
+ [
19
+ "2.3",
20
+ "2.4",
21
+ "2.5",
22
+ "2.6",
23
+ "2.7",
24
+ "3.0",
25
+ "3.1",
26
+ "3.2",
27
+ "3.3",
28
+ "3.4",
29
+ "4.0",
30
+ jruby,
31
+ ]
32
+ env:
33
+ CC_TEST_REPORTER_ID: 20a1139ef1830b4f813a10a03d90e8aa179b5226f75e75c5a949b25756ebf558
34
+
35
+ steps:
36
+ # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
37
+ - uses: actions/checkout@v6
38
+
39
+ - name: Setup ruby
40
+ uses: ruby/setup-ruby@v1
41
+ with:
42
+ ruby-version: ${{ matrix.ruby }}
43
+ bundler-cache: true
44
+
45
+ - name: ruby version
46
+ run: ruby -v
47
+
48
+ - name: Run rspec
49
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -4,6 +4,8 @@
4
4
  /_yardoc/
5
5
  /coverage/
6
6
  /doc/
7
+ /docs/plans/
8
+ /.worktrees/
7
9
  /pkg/
8
10
  /spec/reports/
9
11
  /tmp/
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
- --require spec_helper
2
1
  --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml CHANGED
@@ -1,6 +1,13 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ TargetRubyVersion: 2.3
4
+
1
5
  Style/StringLiterals:
2
6
  EnforcedStyle: double_quotes
3
7
 
8
+ Style/StringLiteralsInInterpolation:
9
+ EnforcedStyle: double_quotes
10
+
4
11
  Style/Documentation:
5
12
  Enabled: false
6
13
 
@@ -10,12 +17,6 @@ Style/TrailingCommaInArguments:
10
17
  Lint/InheritException:
11
18
  Enabled: false
12
19
 
13
- Layout/IndentArray:
14
- Enabled: false
15
-
16
- Layout/IndentHash:
17
- Enabled: false
18
-
19
20
  Style/NegatedIf:
20
21
  Enabled: false
21
22
 
@@ -25,7 +26,7 @@ Metrics/ClassLength:
25
26
  Metrics/ModuleLength:
26
27
  Enabled: false
27
28
 
28
- Metrics/LineLength:
29
+ Layout/LineLength:
29
30
  Max: 120
30
31
 
31
32
  Metrics/MethodLength:
@@ -36,3 +37,6 @@ Metrics/BlockLength:
36
37
 
37
38
  Metrics/AbcSize:
38
39
  Enabled: false
40
+
41
+ Style/TrailingCommaInArrayLiteral:
42
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,122 +1,160 @@
1
- ## HEAD
1
+ # HEAD
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
+
9
+ ## 3.4.0
10
+
11
+ - Add `retry_if` option to support custom retry predicates, including checks against wrapped `exception.cause` values.
12
+
13
+ ## 3.3.0
14
+
15
+ - Refactor `Retriable.retriable` internals into focused private helpers to improve readability while preserving behavior.
16
+ - Modernize `.rubocop.yml` with explicit modern defaults to enable new cops while preserving existing project style policies.
17
+
18
+ ## 3.2.1
19
+
20
+ - Remove executables from gemspec as it was polluting the path for some users. Thanks @hsbt.
21
+
22
+ ## 3.2.0
23
+
24
+ - Require ruby 2.3+.
25
+ - Fix: Ensure `tries` value is overridden by `intervals` parameter if both are provided and add a test for this. This is always what the README stated but the code didn't actually do it.
26
+ - Fix: Some rubocop offenses.
2
27
 
3
28
  ## 3.1.2
4
29
 
5
- * Replace `minitest` gem with `rspec`
6
- * Fancier README
7
- * Remove unnecessary short circuit in `randomize` method
30
+ - Replace `minitest` gem with `rspec`
31
+ - Fancier README
32
+ - Remove unnecessary short circuit in `randomize` method
8
33
 
9
34
  ## 3.1.1
10
35
 
11
- * Fix typo in contexts exception message.
12
- * Fix updating the version in the library.
36
+ - Fix typo in contexts exception message.
37
+ - Fix updating the version in the library.
13
38
 
14
39
  ## 3.1.0
15
40
 
16
- * Added [contexts feature](https://github.com/kamui/retriable#contexts). Thanks to @apurvis.
41
+ - Added [contexts feature](https://github.com/kamui/retriable#contexts). Thanks to @apurvis.
17
42
 
18
43
  ## 3.0.2
19
44
 
20
- * Add configuration and options validation.
45
+ - Add configuration and options validation.
21
46
 
22
47
  ## 3.0.1
23
- * Add `rubocop` linter to enforce coding styles for this library. Also, fix rule violations.
24
- * Removed `attr_reader :config` that caused a warning. @bruno-
25
- * Clean up Rakefile testing cruft. @bruno-
26
- * Use `.any?` in the `:on` hash processing. @apurvis
48
+
49
+ - Add `rubocop` linter to enforce coding styles for this library. Also, fix rule violations.
50
+ - Removed `attr_reader :config` that caused a warning. @bruno-
51
+ - Clean up Rakefile testing cruft. @bruno-
52
+ - Use `.any?` in the `:on` hash processing. @apurvis
27
53
 
28
54
  ## 3.0.0
29
- * Require ruby 2.0+.
30
- * Breaking Change: `on` with a `Hash` value now matches subclassed exceptions. Thanks @apurvis!
31
- * Remove `awesome_print` from development environment.
55
+
56
+ - Require ruby 2.0+.
57
+ - Breaking Change: `on` with a `Hash` value now matches subclassed exceptions. Thanks @apurvis!
58
+ - Remove `awesome_print` from development environment.
32
59
 
33
60
  ## 2.1.0
34
61
 
35
- * Fix bug #17 due to confusing the initial try as a retry.
36
- * Switch to `Minitest` 5.6 expect syntax.
62
+ - Fix bug #17 due to confusing the initial try as a retry.
63
+ - Switch to `Minitest` 5.6 expect syntax.
37
64
 
38
65
  ## 2.0.2
39
66
 
40
- * Change required_ruby_version in gemspec to >= 1.9.3.
67
+ - Change required_ruby_version in gemspec to >= 1.9.3.
41
68
 
42
69
  ## 2.0.1
43
70
 
44
- * Add support for ruby 1.9.3.
71
+ - Add support for ruby 1.9.3.
45
72
 
46
73
  ## 2.0.0
47
74
 
48
- * Require ruby 2.0+.
49
- * Time intervals default to randomized exponential backoff instead of fixed time intervals. The delay between retries grows with every attempt and there's a randomization factor added to each attempt.
50
- * `base_interval`, `max_interval`, `rand_factor`, and `multiplier` are new arguments that are used to generate randomized exponential back off time intervals.
51
- * `interval` argument removed.
52
- * Accept `intervals` array argument to provide your own custom intervals.
53
- * Allow configurable defaults via `Retriable#configure` block.
54
- * Add ability for `:on` argument to accept a `Hash` where the keys are exception types and the values are a single or array of `Regexp` pattern(s) to match against exception messages for retrial.
55
- * Raise, not return, on max elapsed time.
56
- * Check for elapsed time after next interval is calculated and it goes over the max elapsed time.
57
- * Support early termination via `max_elapsed_time` argument.
75
+ - Require ruby 2.0+.
76
+ - Time intervals default to randomized exponential backoff instead of fixed time intervals. The delay between retries grows with every attempt and there's a randomization factor added to each attempt.
77
+ - `base_interval`, `max_interval`, `rand_factor`, and `multiplier` are new arguments that are used to generate randomized exponential back off time intervals.
78
+ - `interval` argument removed.
79
+ - Accept `intervals` array argument to provide your own custom intervals.
80
+ - Allow configurable defaults via `Retriable#configure` block.
81
+ - Add ability for `:on` argument to accept a `Hash` where the keys are exception types and the values are a single or array of `Regexp` pattern(s) to match against exception messages for retrial.
82
+ - Raise, not return, on max elapsed time.
83
+ - Check for elapsed time after next interval is calculated and it goes over the max elapsed time.
84
+ - Support early termination via `max_elapsed_time` argument.
58
85
 
59
86
  ## 2.0.0.beta5
60
- * Change `:max_tries` back to `:tries`.
87
+
88
+ - Change `:max_tries` back to `:tries`.
61
89
 
62
90
  ## 2.0.0.beta4
63
- * Change #retry back to #retriable. Didn't like the idea of defining a method that is also a reserved word.
64
- * Add ability for `:on` argument to accept a `Hash` where the keys are exception types and the values are a single or array of `Regexp` pattern(s) to match against exception messages for retrial.
91
+
92
+ - Change #retry back to #retriable. Didn't like the idea of defining a method that is also a reserved word.
93
+ - Add ability for `:on` argument to accept a `Hash` where the keys are exception types and the values are a single or array of `Regexp` pattern(s) to match against exception messages for retrial.
65
94
 
66
95
  ## 2.0.0.beta3
67
- * Accept `intervals` array argument to provide your own custom intervals.
68
- * Refactor the exponential backoff code into it's own class.
69
- * Add specs for exponential backoff, randomization, and config.
96
+
97
+ - Accept `intervals` array argument to provide your own custom intervals.
98
+ - Refactor the exponential backoff code into it's own class.
99
+ - Add specs for exponential backoff, randomization, and config.
70
100
 
71
101
  ## 2.0.0.beta2
72
- * Raise, not return, on max elapsed time.
73
- * Check for elapsed time after next interval is calculated and it goes over the max elapsed time.
74
- * Add specs for `max_elapsed_time` and `max_interval`.
102
+
103
+ - Raise, not return, on max elapsed time.
104
+ - Check for elapsed time after next interval is calculated and it goes over the max elapsed time.
105
+ - Add specs for `max_elapsed_time` and `max_interval`.
75
106
 
76
107
  ## 2.0.0.beta1
77
- * Require ruby 2.0+.
78
- * Default to random exponential backoff, removes the `interval` option. Exponential backoff is configurable via arguments.
79
- * Allow configurable defaults via `Retriable#configure` block.
80
- * Change `Retriable.retriable` to `Retriable.retry`.
81
- * Support early termination via `max_elapsed_time` argument.
108
+
109
+ - Require ruby 2.0+.
110
+ - Default to random exponential backoff, removes the `interval` option. Exponential backoff is configurable via arguments.
111
+ - Allow configurable defaults via `Retriable#configure` block.
112
+ - Change `Retriable.retriable` to `Retriable.retry`.
113
+ - Support early termination via `max_elapsed_time` argument.
82
114
 
83
115
  ## 1.4.1
84
- * Fixes non kernel mode bug. Remove DSL class, move `#retriable` into Retriable module. Thanks @mkrogemann.
116
+
117
+ - Fixes non kernel mode bug. Remove DSL class, move `#retriable` into Retriable module. Thanks @mkrogemann.
85
118
 
86
119
  ## 1.4.0
87
- * By default, retriable doesn't monkey patch `Kernel`. If you want this functionality,
88
- you can `require 'retriable/core_ext/kernel'.
89
- * Upgrade minitest to 5.x.
90
- * Refactor the DSL into it's own class.
120
+
121
+ - By default, retriable doesn't monkey patch `Kernel`. If you want this functionality,
122
+ you can `require 'retriable/core_ext/kernel'.
123
+ - Upgrade minitest to 5.x.
124
+ - Refactor the DSL into it's own class.
91
125
 
92
126
  ## 1.3.3.1
93
- * Allow sleep parameter to be a proc/lambda to allow for exponential backoff.
127
+
128
+ - Allow sleep parameter to be a proc/lambda to allow for exponential backoff.
94
129
 
95
130
  ## 1.3.3
96
- * sleep after executing the retry block, so there's no wait on the first call (molfar)
131
+
132
+ - sleep after executing the retry block, so there's no wait on the first call (molfar)
97
133
 
98
134
  ## 1.3.2
99
- * Clean up option defaults.
100
- * By default, rescue StandardError and Timeout::Error instead of [Exception](http://www.mikeperham.com/2012/03/03/the-perils-of-rescue-exception).
135
+
136
+ - Clean up option defaults.
137
+ - By default, rescue StandardError and Timeout::Error instead of [Exception](http://www.mikeperham.com/2012/03/03/the-perils-of-rescue-exception).
101
138
 
102
139
  ## 1.3.1
103
- * Add `rake` dependency for travis-ci.
104
- * Update gemspec summary and description.
140
+
141
+ - Add `rake` dependency for travis-ci.
142
+ - Update gemspec summary and description.
105
143
 
106
144
  ## 1.3.0
107
145
 
108
- * Rewrote a lot of the code with inspiration from [attempt](https://rubygems.org/gems/attempt).
109
- * Add timeout option to the code block.
110
- * Include in Kernel by default, but allow require 'retriable/no_kernel' to load a non kernel version.
111
- * Renamed `:times` option to `:tries`.
112
- * Renamed `:sleep` option to `:interval`.
113
- * Renamed `:then` option to `:on_retry`.
114
- * Removed other callbacks, you can wrap retriable in a begin/rescue/else/ensure block if you need that functionality. It avoids the need to define multiple Procs and makes the code more readable.
115
- * Rewrote most of the README
146
+ - Rewrote a lot of the code with inspiration from [attempt](https://rubygems.org/gems/attempt).
147
+ - Add timeout option to the code block.
148
+ - Include in Kernel by default, but allow require 'retriable/no_kernel' to load a non kernel version.
149
+ - Renamed `:times` option to `:tries`.
150
+ - Renamed `:sleep` option to `:interval`.
151
+ - Renamed `:then` option to `:on_retry`.
152
+ - Removed other callbacks, you can wrap retriable in a begin/rescue/else/ensure block if you need that functionality. It avoids the need to define multiple Procs and makes the code more readable.
153
+ - Rewrote most of the README
116
154
 
117
155
  ## 1.2.0
118
156
 
119
- * Forked the retryable-rb repo.
120
- * Extend the Kernel module with the retriable method so you can use it anywhere without having to include it in every class.
121
- * Update gemspec, Gemfile, and Raketask.
122
- * Remove echoe dependency.
157
+ - Forked the retryable-rb repo.
158
+ - Extend the Kernel module with the retriable method so you can use it anywhere without having to include it in every class.
159
+ - Update gemspec, Gemfile, and Raketask.
160
+ - Remove echoe dependency.
@@ -0,0 +1,10 @@
1
+ # Code of Conduct
2
+
3
+ "retriable" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
4
+
5
+ * Participants will be tolerant of opposing views.
6
+ * Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
7
+ * When interpreting the words and actions of others, participants should always assume good intentions.
8
+ * Behaviour which can be reasonably considered harassment will not be tolerated.
9
+
10
+ If you have any concerns about behaviour within this project, please contact us at ["jack@jackchu.com"](mailto:"jack@jackchu.com").
data/Gemfile CHANGED
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  gemspec
4
6
 
5
7
  group :test do
6
- gem "codeclimate-test-reporter", require: false
7
- gem "rspec"
8
+ gem "rspec", "~> 3.0"
8
9
  gem "simplecov", require: false
9
10
  end
10
11
 
@@ -14,4 +15,5 @@ end
14
15
 
15
16
  group :development, :test do
16
17
  gem "pry"
18
+ gem "rake", "~> 13.0"
17
19
  end
data/README.md CHANGED
@@ -1,14 +1,15 @@
1
1
  # Retriable
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/kamui/retriable.svg)](http://travis-ci.org/kamui/retriable)
4
- [![Code Climate](https://codeclimate.com/github/kamui/retriable/badges/gpa.svg)](https://codeclimate.com/github/kamui/retriable)
5
- [![Test Coverage](https://codeclimate.com/github/kamui/retriable/badges/coverage.svg)](https://codeclimate.com/github/kamui/retriable)
3
+ ![Build Status](https://github.com/kamui/retriable/actions/workflows/main.yml/badge.svg)
4
+ [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)
6
5
 
7
6
  Retriable is a simple DSL to retry failed code blocks with randomized [exponential backoff](http://en.wikipedia.org/wiki/Exponential_backoff) time intervals. This is especially useful when interacting external APIs, remote services, or file system calls.
8
7
 
9
8
  ## Requirements
10
9
 
11
- Ruby 2.0.0+
10
+ Ruby 2.3.0+
11
+
12
+ If you need ruby 2.0.0-2.2.x support, use the [3.1 branch](https://github.com/kamui/retriable/tree/3.1.x) by specifying `~3.1` in your Gemfile.
12
13
 
13
14
  If you need ruby 1.9.3 support, use the [2.x branch](https://github.com/kamui/retriable/tree/2.x) by specifying `~2.1` in your Gemfile.
14
15
 
@@ -31,10 +32,11 @@ require 'retriable'
31
32
  In your Gemfile:
32
33
 
33
34
  ```ruby
34
- gem 'retriable', '~> 3.1'
35
+ gem 'retriable', '~> 3.4'
35
36
  ```
36
37
 
37
38
  ## Usage
39
+
38
40
  Code in a `Retriable.retriable` block will be retried if an exception is raised.
39
41
 
40
42
  ```ruby
@@ -51,45 +53,49 @@ end
51
53
  ```
52
54
 
53
55
  ### Defaults
56
+
54
57
  By default, `Retriable` will:
55
- * rescue any exception inherited from `StandardError`
56
- * make 3 tries (including the initial attempt) before raising the last exception
57
- * use randomized exponential backoff to calculate each succeeding try interval.
58
58
 
59
- The default interval table with 10 tries looks like this (in seconds, rounded to the nearest millisecond):
59
+ - rescue any exception inherited from `StandardError`
60
+ - make 3 tries (including the initial attempt) before raising the last exception
61
+ - use randomized exponential backoff to calculate each succeeding try interval.
60
62
 
61
- | Retry # | Min | Average | Max |
62
- | -------- | -------- | -------- | -------- |
63
- | 1 | `0.25` | `0.5` | `0.75` |
64
- | 2 | `0.375` | `0.75` | `1.125` |
65
- | 3 | `0.563` | `1.125` | `1.688` |
66
- | 4 | `0.844` | `1.688` | `2.531` |
67
- | 5 | `1.266` | `2.531` | `3.797` |
68
- | 6 | `1.898` | `3.797` | `5.695` |
69
- | 7 | `2.848` | `5.695` | `8.543` |
70
- | 8 | `4.271` | `8.543` | `12.814` |
71
- | 9 | `6.407` | `12.814` | `19.222` |
72
- | 10 | **stop** | **stop** | **stop** |
63
+ The default interval table with 10 tries looks like this (in seconds, rounded to the nearest millisecond):
73
64
 
65
+ | Retry # | Min | Average | Max |
66
+ | ------- | -------- | -------- | -------- |
67
+ | 1 | `0.25` | `0.5` | `0.75` |
68
+ | 2 | `0.375` | `0.75` | `1.125` |
69
+ | 3 | `0.563` | `1.125` | `1.688` |
70
+ | 4 | `0.844` | `1.688` | `2.531` |
71
+ | 5 | `1.266` | `2.531` | `3.797` |
72
+ | 6 | `1.898` | `3.797` | `5.695` |
73
+ | 7 | `2.848` | `5.695` | `8.543` |
74
+ | 8 | `4.271` | `8.543` | `12.814` |
75
+ | 9 | `6.407` | `12.814` | `19.222` |
76
+ | 10 | **stop** | **stop** | **stop** |
74
77
 
75
78
  ### Options
76
79
 
77
80
  Here are the available options, in some vague order of relevance to most common use patterns:
78
81
 
79
- | Option | Default | Definition |
80
- | ------ | ------- | ---------- |
81
- | **`tries`** | `3` | Number of attempts to make at running your code block (includes initial attempt). |
82
- | **`on`** | `[StandardError]` | Type of exceptions to retry. [Read more](#configuring-which-options-to-retry-with-on). |
83
- | **`on_retry`** | `nil` | `Proc` to call after each try is rescued. [Read more](#callbacks). |
84
- | **`base_interval`** | `0.5` | The initial interval in seconds between tries. |
85
- | **`max_elapsed_time`** | `900` (15 min) | The maximum amount of total time in seconds that code is allowed to keep being retried. |
86
- | **`max_interval`** | `60` | The maximum interval in seconds that any individual retry can reach. |
87
- | **`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. |
88
- | **`timeout`** | `nil` | Number of seconds to allow the code block to run before raising a `Timeout::Error` inside each try. `nil` means the code block can run forever without raising error. (You may want to read up on [the dangers of using Ruby `Timeout`](https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying/) before using this feature.) |
89
- | **`rand_factor`** | `0.25` | 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])` |
90
- | **`intervals`** | `nil` | Skip generated intervals and provide your own array of intervals in seconds. [Read more](#custom-interval-array). |
82
+ | Option | Default | Definition |
83
+ | ---------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
84
+ | **`tries`** | `3` | Number of attempts to make at running your code block (includes initial attempt). |
85
+ | **`on`** | `[StandardError]` | Type of exceptions to retry. [Read more](#configuring-which-options-to-retry-with-on). |
86
+ | **`retry_if`** | `nil` | Callable (for example a `Proc` or lambda) that receives the rescued exception and returns true/false to decide whether to retry. [Read more](#advanced-retry-matching-with-retry_if). |
87
+ | **`on_retry`** | `nil` | `Proc` to call after each try is rescued. [Read more](#callbacks). |
88
+ | **`sleep_disabled`** | `false` | When true, disable exponential backoff and attempt retries immediately. |
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. Set to `nil` to disable the time limit and retry based solely on `tries`. |
91
+ | **`max_interval`** | `60` | The maximum interval in seconds that any individual retry can reach. |
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
+ | **`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])` |
94
+ | **`intervals`** | `nil` | Skip generated intervals and provide your own array of intervals in seconds. [Read more](#custom-interval-array). |
95
+ | **`timeout`** | `nil` | Number of seconds to allow the code block to run before raising a `Timeout::Error` inside each try. `nil` means the code block can run forever without raising error. The implementation uses `Timeout::timeout`, which may be [unsafe](https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying/) [and](http://blog.headius.com/2008/02/ruby-threadraise-threadkill-timeoutrb.html) [even](https://adamhooper.medium.com/in-ruby-dont-use-timeout-77d9d4e5a001) [dangerous](https://www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/). Proceed with caution. |
91
96
 
92
97
  #### Configuring Which Options to Retry With :on
98
+
93
99
  **`:on`** Can take the form:
94
100
 
95
101
  - An `Exception` class (retry every exception of this type, including subclasses)
@@ -99,6 +105,31 @@ Here are the available options, in some vague order of relevance to most common
99
105
  - A single `Regexp` pattern (retries exceptions ONLY if their `message` matches the pattern)
100
106
  - An array of patterns (retries exceptions ONLY if their `message` matches at least one of the patterns)
101
107
 
108
+ #### Advanced Retry Matching With :retry_if
109
+
110
+ Use **`:retry_if`** when retry logic depends on details that `:on` does not cover. The Proc receives the rescued exception and should return `true` to retry or `false` to re-raise immediately.
111
+
112
+ ```ruby
113
+ def caused_by?(error, klass)
114
+ current = error
115
+ while current
116
+ return true if current.is_a?(klass)
117
+
118
+ current = current.cause
119
+ end
120
+
121
+ false
122
+ end
123
+
124
+ Retriable.retriable(
125
+ on: [Faraday::ConnectionFailed],
126
+ retry_if: ->(exception) { caused_by?(exception, Errno::ECONNRESET) }
127
+ ) do
128
+ # code here...
129
+ end
130
+ ```
131
+
132
+ `:retry_if` runs after the exception type has matched `:on`.
102
133
 
103
134
  ### Configuration
104
135
 
@@ -129,7 +160,7 @@ Retriable.retriable(on: [Timeout::Error, Errno::ECONNRESET]) do
129
160
  end
130
161
  ```
131
162
 
132
- You can also use a hash to specify that you only want to retry exceptions with certain messages (see [the documentation above](#configuring-which-options-to-retry-with-on)). This example will retry all `ActiveRecord::RecordNotUnique` exceptions, `ActiveRecord::RecordInvalid` exceptions where the message matches either `/Parent must exist/` or `/Username has already been taken/`, or `Mysql2::Error` exceptions where the message matches `/Duplicate entry/`.
163
+ You can also use a hash to specify that you only want to retry exceptions with certain messages (see [the documentation above](#configuring-which-options-to-retry-with-on)). This example will retry all `ActiveRecord::RecordNotUnique` exceptions, `ActiveRecord::RecordInvalid` exceptions where the message matches either `/Parent must exist/` or `/Username has already been taken/`, or `Mysql2::Error` exceptions where the message matches `/Duplicate entry/`.
133
164
 
134
165
  ```ruby
135
166
  Retriable.retriable(on: {
@@ -141,7 +172,9 @@ Retriable.retriable(on: {
141
172
  end
142
173
  ```
143
174
 
144
- You can also specify a timeout if you want the code block to only try for X amount of seconds. This timeout is per try. (You may want to read up on [the dangers of using Ruby `Timeout`](https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying/) before using this feature.)
175
+ You can also specify a timeout if you want the code block to only try for X amount of seconds. This timeout is per try.
176
+
177
+ The implementation uses `Timeout::timeout`, which may be [unsafe](https://jvns.ca/blog/2015/11/27/why-rubys-timeout-is-dangerous-and-thread-dot-raise-is-terrifying/) [and](http://blog.headius.com/2008/02/ruby-threadraise-threadkill-timeoutrb.html) [even](https://adamhooper.medium.com/in-ruby-dont-use-timeout-77d9d4e5a001) [dangerous](https://www.mikeperham.com/2015/05/08/timeout-rubys-most-dangerous-api/). You can use this option, but you need to be very careful because the code in the block, including libraries or other code it calls, could be interrupted by the timeout at any line. You must ensure you have the right rescue logic and guards in place ([Thread.handle_interrupt](https://www.rubydoc.info/stdlib/core/Thread.handle_interrupt)) to handle that possible behavior. If that's not possible, the recommendation is that you're better off impelenting your own timeout methods depending on what your code is doing than use this feature.
145
178
 
146
179
  ```ruby
147
180
  Retriable.retriable(timeout: 60) do
@@ -171,7 +204,7 @@ This example makes 5 total attempts. If the first attempt fails, the 2nd attempt
171
204
 
172
205
  ### Turn off Exponential Backoff
173
206
 
174
- Exponential backoff is enabled by default. If you want to simply retry code every second, 5 times maximum, you can do this:
207
+ Exponential backoff is enabled by default. If you want to simply retry code every second, 5 times maximum, you can do this:
175
208
 
176
209
  ```ruby
177
210
  Retriable.retriable(tries: 5, base_interval: 1.0, multiplier: 1.0, rand_factor: 0.0) do
@@ -179,7 +212,7 @@ Retriable.retriable(tries: 5, base_interval: 1.0, multiplier: 1.0, rand_factor:
179
212
  end
180
213
  ```
181
214
 
182
- This works by starting at a 1 second `base_interval`. Setting the `multipler` to 1.0 means each subsequent try will increase 1x, which is still `1.0` seconds, and then a `rand_factor` of 0.0 means that there's no randomization of that interval. (By default, it would randomize 0.25 seconds, which would mean normally the intervals would randomize between 0.75 and 1.25 seconds, but in this case `rand_factor` is basically being disabled.)
215
+ This works by starting at a 1 second `base_interval`. Setting the `multipler` to 1.0 means each subsequent try will increase 1x, which is still `1.0` seconds, and then a `rand_factor` of 0.0 means that there's no randomization of that interval. (By default, it would randomize 0.5 seconds, which would mean normally the intervals would randomize between 0.5 and 1.5 seconds, but in this case `rand_factor` is basically being disabled.)
183
216
 
184
217
  Another way to accomplish this would be to create an array with a fixed interval. In this example, `Array.new(5, 1)` creates an array with 5 elements, all with the value 1. The code block will retry up to 5 times, and wait 1 second between each attempt.
185
218
 
@@ -223,7 +256,7 @@ begin
223
256
  # some code
224
257
  end
225
258
  rescue => e
226
- # run this if retriable ends up re-rasing the exception
259
+ # run this if retriable ends up re-raising the exception
227
260
  else
228
261
  # run this if retriable doesn't raise any exceptions
229
262
  ensure
@@ -233,7 +266,7 @@ end
233
266
 
234
267
  ## Contexts
235
268
 
236
- Contexts allow you to coordinate sets of Retriable options across an application. Each context is basically an argument hash for `Retriable.retriable` that is stored in the `Retriable.config` as a simple `Hash` and is accessible by name. For example:
269
+ Contexts allow you to coordinate sets of Retriable options across an application. Each context is basically an argument hash for `Retriable.retriable` that is stored in the `Retriable.config` as a simple `Hash` and is accessible by name. For example:
237
270
 
238
271
  ```ruby
239
272
  Retriable.configure do |c|
@@ -322,6 +355,8 @@ Retriable.configure do |c|
322
355
  end
323
356
  ```
324
357
 
358
+ Note: In this and the following examples, `Retriable.configure` sets a default config, it doesn't override the configuration for the `retriable` method calls. Calling `Retriable.retriable` with options will override the default configuration for that call. So if you have `tries` set to 5 in `Retriable.configure`, but then you call `Retriable.retriable(tries: 3)`, that call will use 3 tries instead of 5. The configuration is basically a default set of options that can be overridden by passing options to the `retriable` method or by using contexts.
359
+
325
360
  Alternately, if you are using RSpec, you could override the Retriable confguration in your `spec_helper`.
326
361
 
327
362
  ```ruby
@@ -334,6 +369,7 @@ end
334
369
  If you have defined contexts for your configuration, you'll need to change values for each context, because those values take precedence over the default configured value.
335
370
 
336
371
  For example assuming you have configured a `google_api` context:
372
+
337
373
  ```ruby
338
374
  # config/initializers/retriable.rb
339
375
  Retriable.configure do |c|
@@ -366,21 +402,14 @@ Retriable.configure do |c|
366
402
  end
367
403
  ```
368
404
 
369
- ## Proxy Wrapper Object
370
-
371
- [@julik](https://github.com/julik) has created a gem called [retriable_proxy](https://github.com/julik/retriable_proxy) that extends `retriable` with the ability to wrap objects and specify which methods you want to be retriable, like so:
372
-
373
- ```ruby
374
- # api_endpoint is an instance of some kind of class that connects to an API
375
- RetriableProxy.for_object(api_endpoint, on: Net::TimeoutError)
376
- ```
377
-
378
405
  ## Credits
379
406
 
380
407
  The randomized exponential backoff implementation was inspired by the one used in Google's [google-http-java-client](https://code.google.com/p/google-http-java-client/wiki/ExponentialBackoff) project.
381
408
 
382
409
  ## Development
410
+
383
411
  ### Running Specs
412
+
384
413
  ```bash
385
414
  bundle exec rspec
386
415
  ```