block_repeater 1.0.0 → 1.1.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/.github/workflows/gem-push.yml +1 -3
- data/.gitignore +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +18 -2
- data/lib/block_repeater/repeater.rb +35 -2
- data/lib/block_repeater/version.rb +1 -1
- 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: 338c684e8ff15a822ae560f39d1de4df380f16213bb8f5fb4d1099f98b06f627
|
|
4
|
+
data.tar.gz: f02a5d355851bf5b1b089bb2a86ff5f4325a76ca260969385aee159fcc0f6e86
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9013a8cb077a212b9896bc30d5a1d6bfc7be81f3655b25562307e369a0a6d125b8aae352a5ff0a15046b8899304d0c79c3bf5bc9e8179681bd38bb8345d32ac8
|
|
7
|
+
data.tar.gz: 1b53289cec53d69c0b3a9cce35b685567e8780c350a900e58f1abc9c3e17779d3a3528befce6583b506fe20c95a12ae4036a11b20516454a8e756141235fe6b0
|
|
@@ -3,15 +3,13 @@ name: Ruby Gem
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
branches: [ "master" ]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [ "master" ]
|
|
8
6
|
|
|
9
7
|
jobs:
|
|
10
8
|
test:
|
|
11
9
|
runs-on: ubuntu-latest
|
|
12
10
|
strategy:
|
|
13
11
|
matrix:
|
|
14
|
-
ruby-version: [ '3.0', '3.1' ]
|
|
12
|
+
ruby-version: [ '3.0', '3.1', '3.2' ]
|
|
15
13
|
|
|
16
14
|
steps:
|
|
17
15
|
- uses: actions/checkout@v2
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -50,6 +50,22 @@ The repeater also takes two parameters:
|
|
|
50
50
|
repeat (delay: 0.5, times: 10){ call_database_method }.until{ |result| result.count.positive? }
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
### Backoff method
|
|
54
|
+
This is a slightly different take on the preferred `repeat` method. It retries a call whilst exponentially increasing the wait time between each iteration until a timeout is reached.
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
repeat do
|
|
58
|
+
call_method
|
|
59
|
+
end.until do |result|
|
|
60
|
+
result
|
|
61
|
+
end.backoff(timeout: 10, initial_wait: 0.5, multiplier: 2)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`backoff` takes three paramaters:
|
|
65
|
+
- `timeout:` is how long you want your repeater to run
|
|
66
|
+
- `initial_wait:` is how long you want to pause before your first retry
|
|
67
|
+
- `multiplier:` is the rate at which you increase the wait time between each iteration
|
|
68
|
+
|
|
53
69
|
### Exception Handling
|
|
54
70
|
Using the `catch` method you can define how the repeater should respond to specific exception types. To do this you need to provide a list of exceptions to catch, a block of code which will be performed, and an option for how to trigger than block of code.
|
|
55
71
|
|
|
@@ -82,13 +98,13 @@ You can also define default exception handling behaviour which all repeaters in
|
|
|
82
98
|
```ruby
|
|
83
99
|
BlockRepeater::Repeater.default_catch(exceptions: [IOError], behaviour: :defer) do |e|
|
|
84
100
|
puts 'An IOError occurred'
|
|
85
|
-
e
|
|
101
|
+
raise e
|
|
86
102
|
end
|
|
87
103
|
```
|
|
88
104
|
A common use-case for default exception handling is if using a gem such as RSpec, where you may want to handle failed expectations in a uniform manner. To do so you need define the default behaviour first, in a place such as a `env.rb` file or similar:
|
|
89
105
|
```ruby
|
|
90
106
|
BlockRepeater::Repeater.default_catch(exceptions: [RSpec::Expectations::ExpectationNotMetError], behaviour: :defer) do |e|
|
|
91
|
-
e
|
|
107
|
+
raise e
|
|
92
108
|
end
|
|
93
109
|
```
|
|
94
110
|
Then an RSpec expectation can be used in the block for the `until` method. The expectation will be attempted each try, but the exception will only be raised if it has still failed once the number or attempts has been reached.
|
|
@@ -45,8 +45,8 @@ module BlockRepeater
|
|
|
45
45
|
deferred_exception = nil
|
|
46
46
|
rescue *exception_types => e
|
|
47
47
|
exceptions = if anticipated_exception_types.any? do |ex|
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
e.class <= ex
|
|
49
|
+
end
|
|
50
50
|
@anticipated_exceptions
|
|
51
51
|
else
|
|
52
52
|
@@default_exceptions
|
|
@@ -72,6 +72,39 @@ module BlockRepeater
|
|
|
72
72
|
result
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
+
# Retry a call whilst exponentially increasing the wait time between each iteration until a timeout is reached
|
|
76
|
+
# @param [Integer] `timeout` is the max amount wait of time you wish to try the action
|
|
77
|
+
# @param [Integer] `initial_wait` is the initial wait time to retry the action
|
|
78
|
+
# @param [Integer] `multiplier` is the rate at which you increase the wait time between each iteration
|
|
79
|
+
def backoff(timeout: 10, initial_wait: 0.1, multiplier: 2)
|
|
80
|
+
raise StandardError, 'Multiplier cannot be less than 1.1' if multiplier < 1.1
|
|
81
|
+
|
|
82
|
+
condition_met = nil
|
|
83
|
+
result = nil
|
|
84
|
+
|
|
85
|
+
current_sleep_seconds = initial_wait
|
|
86
|
+
start_time = Time.now
|
|
87
|
+
|
|
88
|
+
until current_sleep_seconds >= timeout
|
|
89
|
+
result = @repeat_block.call
|
|
90
|
+
condition_met = @condition_block.call(result) if @condition_block
|
|
91
|
+
|
|
92
|
+
duration = Time.now - start_time
|
|
93
|
+
|
|
94
|
+
break if condition_met || duration > timeout
|
|
95
|
+
|
|
96
|
+
# calculating exponential increase
|
|
97
|
+
current_sleep_seconds *= multiplier
|
|
98
|
+
# how long the total duration will be after the next sleep
|
|
99
|
+
projected_duration = current_sleep_seconds + duration
|
|
100
|
+
# if projected duration exceeds the timeout, reduce time for next sleep to allow one final call
|
|
101
|
+
current_sleep_seconds = (timeout - duration) if projected_duration > timeout
|
|
102
|
+
|
|
103
|
+
sleep(current_sleep_seconds)
|
|
104
|
+
end
|
|
105
|
+
result
|
|
106
|
+
end
|
|
107
|
+
|
|
75
108
|
##
|
|
76
109
|
# Determine how to respond to exceptions raised while repeating, must be called _before_ #until
|
|
77
110
|
#
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: block_repeater
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- William Bray
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-05-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bump
|
|
@@ -141,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
141
141
|
- !ruby/object:Gem::Version
|
|
142
142
|
version: '0'
|
|
143
143
|
requirements: []
|
|
144
|
-
rubygems_version: 3.
|
|
144
|
+
rubygems_version: 3.2.15
|
|
145
145
|
signing_key:
|
|
146
146
|
specification_version: 4
|
|
147
147
|
summary: Conditionally repeat a block of code
|