activejob-retry 0.4.2 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5143405bed9e31a9105b3dc8d245f6e6d6b3f772
4
- data.tar.gz: 029ae74c9cce202706f109991d67b07404cef2fc
3
+ metadata.gz: 60dfb14cc0c6a91446c784b4e8411e9aae47c7ee
4
+ data.tar.gz: a718488ecd619792443718c66ecea001eeeb5266
5
5
  SHA512:
6
- metadata.gz: a34362c6832bf49579a692d5219d808a46ccc2a89c9ebe6b02e8a53f8158091a20ce9e546697f3b78bc7c3a9294e84ec9cf0f8fb096f4d7c444e0f54f08f22d2
7
- data.tar.gz: 5b3457112e0080fd42c0e9f288b89c8fd15cf473b6ce815a801be010949ed21a8555425503dd9b5b6cf08294384ee7383039e3c12fa31231ba3774395ac985c6
6
+ metadata.gz: 697ffb8e3dba15591d96f1f9c65d8bd75692266c1c90e64eb527eb6bccceb0bca21838b1f348a9afcfbdb3b9634743f544bbbc98e570c12b790776fe6b5e0c3e
7
+ data.tar.gz: d894718b172f33037f94089b54b6cb39d62e23c2b1df82a9ff8a70a48d6665c1bdc38a62d6b5ba813243516856fc9edbe4036df28d3aaacd81b148248651d377
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## 0.5.0 - July 23, 2015
2
+
3
+ - Add exponential backoff strategy (by [@DavydenkovM](https://github.com/DavydenkovM))
4
+
5
+ ## 0.4.2 - March 22, 2015
6
+
7
+ - Remove Sidekiq from the problematic adapter blacklist (patch by [@troter](https://github.com/troter))
8
+
9
+ ## 0.4.1 - March 18, 2015
10
+
11
+ - Remove the need for an explicit require (patch by [@isaacseymour](https://github.com/isaacseymour))
12
+
1
13
  ## 0.4.0 - January 16, 2015
2
14
 
3
15
  - Blacklist problematic adapters rather than whitelisting known good ones (patch by [@isaacseymour](https://github.com/isaacseymour))
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- activejob-retry (0.4.2)
4
+ activejob-retry (0.5.0)
5
5
  activejob (>= 4.2)
6
6
  activesupport (>= 4.2)
7
7
 
@@ -207,3 +207,6 @@ DEPENDENCIES
207
207
  sequel
208
208
  sidekiq
209
209
  sqlite3
210
+
211
+ BUNDLED WITH
212
+ 1.10.5
data/README.md CHANGED
@@ -4,7 +4,7 @@ ActiveJob::Retry [![Build Status](https://travis-ci.org/gocardless/activejob-ret
4
4
  **This is an alpha library** in active development, so the API may change.
5
5
 
6
6
  Automatic retry functionality for ActiveJob. Just `include ActiveJob::Retry` in your job
7
- class and call one of `constant_retry`, `variable_retry`, or `retry_with` to define your
7
+ class and call one of `constant_retry`, `variable_retry`, `exponential_retry` or `retry_with` to define your
8
8
  retry strategy:
9
9
 
10
10
  ```ruby
@@ -14,10 +14,13 @@ class ProcessWebhook < ActiveJob::Base
14
14
  queue_as :webhooks
15
15
 
16
16
  # Constant delay between attempts:
17
- constant_retry limit: 3, delay: 5, retryable_exceptions: [TimeoutError, NetworkError]
17
+ constant_retry limit: 3, delay: 5.minutes, retryable_exceptions: [TimeoutError, NetworkError]
18
18
 
19
19
  # Or, variable delay between attempts:
20
- variable_retry delays: [1, 5, 10, 30]
20
+ variable_retry delays: [1.minute, 5.minutes, 10.minutes, 30.minutes]
21
+
22
+ # Or, exponential delay between attempts:
23
+ exponential_retry limit: 25
21
24
 
22
25
  # You can also use a custom backoff strategy by passing an object which responds to
23
26
  # `should_retry?(attempt, exception)`, and `retry_delay(attempt, exception)`
@@ -48,15 +51,23 @@ if the exception is not going to be retried, or has failed the final retry.
48
51
  |:---------------------- |:------- |:-------------- |
49
52
  | `limit` | `1` | Maximum number of times to attempt the job (default: 1).
50
53
  | `unlimited_retries` | `false` | If set to `true`, this job will be repeated indefinitely until in succeeds. Use with extreme caution.
51
- | `delay` | `0` | Time between attempts (default: 0).
54
+ | `delay` | `0` | Time between attempts in seconds (default: 0).
52
55
  | `retryable_exceptions` | `nil` | A whitelist of exceptions to retry. When `nil`, all exceptions will result in a retry.
53
56
  | `fatal_exceptions` | `[]` | A blacklist of exceptions to not retry (default: []).
54
57
 
58
+ #### exponential_retry options
59
+ | Option | Default | Description |
60
+ |:---------------------- |:------- |:-------------- |
61
+ | `limit` | `1` | Maximum number of times to attempt the job (default: 1).
62
+ | `unlimited_retries` | `false` | If set to `true`, this job will be repeated indefinitely until in succeeds. Use with extreme caution.
63
+ | `retryable_exceptions` | `nil` | Same as for [constant_retry](#constant_retry-options).
64
+ | `fatal_exceptions` | `[]` | Same as for [constant_retry](#constant_retry-options).
65
+
55
66
  #### variable_retry options
56
67
 
57
68
  | Option | Default | Description |
58
69
  |:---------------------- |:------- |:------------- |
59
- | `delays` | | __required__ An array of delays between attempts. The first attempt will occur whenever you originally enqueued the job to happen.
70
+ | `delays` | | __required__ An array of delays between attempts in seconds. The first attempt will occur whenever you originally enqueued the job to happen.
60
71
  | `min_delay_multiplier` | | If supplied, each delay will be multiplied by a random number between this and `max_delay_multiplier`.
61
72
  | `max_delay_multiplier` | | The other end of the range for `min_delay_multiplier`. If one is supplied, both must be.
62
73
  | `retryable_exceptions` | `nil` | Same as for [constant_retry](#constant_retry-options).
@@ -5,6 +5,7 @@ require 'active_job/retry/version'
5
5
  require 'active_job/retry/errors'
6
6
  require 'active_job/retry/constant_backoff_strategy'
7
7
  require 'active_job/retry/variable_backoff_strategy'
8
+ require 'active_job/retry/exponential_backoff_strategy'
8
9
 
9
10
  unless ActiveJob::Base.method_defined?(:deserialize)
10
11
  require 'active_job/retry/deserialize_monkey_patch'
@@ -45,6 +46,10 @@ module ActiveJob
45
46
  retry_with(VariableBackoffStrategy.new(options))
46
47
  end
47
48
 
49
+ def exponential_retry(options)
50
+ retry_with(ExponentialBackoffStrategy.new(options))
51
+ end
52
+
48
53
  def retry_with(backoff_strategy)
49
54
  unless backoff_strategy_valid?(backoff_strategy)
50
55
  raise InvalidConfigurationError,
@@ -0,0 +1,18 @@
1
+ require 'active_job/retry/exponential_options_validator'
2
+
3
+ module ActiveJob
4
+ module Retry
5
+ class ExponentialBackoffStrategy < ConstantBackoffStrategy
6
+ def initialize(options)
7
+ ExponentialOptionsValidator.new(options).validate!
8
+ @retry_limit = options.fetch(:limit, 1)
9
+ @fatal_exceptions = options.fetch(:fatal_exceptions, [])
10
+ @retryable_exceptions = options.fetch(:retryable_exceptions, nil)
11
+ end
12
+
13
+ def retry_delay(attempt, _exception)
14
+ (attempt**4 + 15 + (rand(30) * (attempt + 1))).seconds
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,79 @@
1
+ require 'active_job/retry/errors'
2
+
3
+ module ActiveJob
4
+ module Retry
5
+ class ExponentialOptionsValidator
6
+ def initialize(options)
7
+ @options = options
8
+ end
9
+
10
+ def validate!
11
+ validate_limit_numericality!
12
+ validate_infinite_limit!
13
+ validate_delay_not_specified!
14
+ validate_not_both_exceptions!
15
+ # Fatal exceptions must be an array (cannot be nil, since then all
16
+ # exceptions would be fatal - for that just set `limit: 0`)
17
+ validate_array_of_exceptions!(:fatal_exceptions)
18
+ # Retryable exceptions must be an array of exceptions or `nil` to retry
19
+ # any exception
20
+ if options[:retryable_exceptions]
21
+ validate_array_of_exceptions!(:retryable_exceptions)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :options
28
+
29
+ # Limit must be an integer >= 0, or nil
30
+ def validate_limit_numericality!
31
+ return unless options[:limit]
32
+ return if options[:limit].is_a?(Fixnum) && options[:limit] >= 0
33
+
34
+ raise InvalidConfigurationError,
35
+ 'Limit must be an integer >= 0, or nil for unlimited retries'
36
+ end
37
+
38
+ # If no limit is supplied, you *must* set `unlimited_retries: true` and
39
+ # understand that your ops team might hurt you.
40
+ def validate_infinite_limit!
41
+ limit = options.fetch(:limit, 1)
42
+ return unless limit.nil? ^ options[:unlimited_retries] == true
43
+
44
+ if limit.nil? && options[:unlimited_retries] != true
45
+ raise InvalidConfigurationError,
46
+ 'You must set `unlimited_retries: true` to use `limit: nil`'
47
+ else
48
+ raise InvalidConfigurationError,
49
+ 'You must set `limit: nil` to have unlimited retries'
50
+ end
51
+ end
52
+
53
+ # Delay must not be set
54
+ def validate_delay_not_specified!
55
+ return unless options[:delay]
56
+
57
+ raise InvalidConfigurationError,
58
+ 'You can`t set delay for ExponentialBackoffStrategy'
59
+ end
60
+
61
+ def validate_not_both_exceptions!
62
+ return unless options[:fatal_exceptions] && options[:retryable_exceptions]
63
+
64
+ raise InvalidConfigurationError,
65
+ 'fatal_exceptions and retryable_exceptions cannot be used together'
66
+ end
67
+
68
+ def validate_array_of_exceptions!(key)
69
+ return unless options[key]
70
+ if options[key].is_a?(Array) &&
71
+ options[key].all? { |ex| ex.is_a?(Class) && ex <= Exception }
72
+ return
73
+ end
74
+
75
+ raise InvalidConfigurationError, "#{key} must be an array of exceptions!"
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,5 +1,5 @@
1
1
  module ActiveJob
2
2
  module Retry
3
- VERSION = '0.4.2'
3
+ VERSION = '0.5.0'
4
4
  end
5
5
  end
@@ -0,0 +1,143 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActiveJob::Retry::ExponentialBackoffStrategy do
4
+ let(:strategy) { described_class.new(options) }
5
+
6
+ describe '#should_retry?' do
7
+ subject { strategy.should_retry?(attempt, exception) }
8
+ let(:attempt) { 1 }
9
+ let(:exception) { RuntimeError.new }
10
+
11
+ context 'when the limit is infinite' do
12
+ let(:options) { { limit: nil, unlimited_retries: true } }
13
+
14
+ context '1st attempt' do
15
+ let(:attempt) { 1 }
16
+ it { is_expected.to be(true) }
17
+ end
18
+
19
+ context '99999th attempt' do
20
+ let(:attempt) { 99_999 }
21
+ it { is_expected.to be(true) }
22
+ end
23
+ end
24
+
25
+ context 'when the limit is 0' do
26
+ let(:options) { { limit: 0 } }
27
+
28
+ context '1st attempt' do
29
+ let(:attempt) { 1 }
30
+ it { is_expected.to be(false) }
31
+ end
32
+
33
+ context '99999th attempt' do
34
+ let(:attempt) { 99_999 }
35
+ it { is_expected.to be(false) }
36
+ end
37
+ end
38
+
39
+ context 'when the limit is 5' do
40
+ let(:options) { { limit: 5 } }
41
+
42
+ context '1st attempt' do
43
+ let(:attempt) { 1 }
44
+ it { is_expected.to be(true) }
45
+ end
46
+
47
+ context '4th attempt' do
48
+ let(:attempt) { 4 }
49
+ it { is_expected.to be(true) }
50
+ end
51
+
52
+ context '5th attempt' do
53
+ let(:attempt) { 5 }
54
+ it { is_expected.to be(false) }
55
+ end
56
+ end
57
+
58
+ context 'defaults (retry everything)' do
59
+ let(:options) { { limit: 10 } }
60
+
61
+ context 'Exception' do
62
+ let(:exception) { Exception.new }
63
+ it { is_expected.to be(true) }
64
+ end
65
+
66
+ context 'RuntimeError' do
67
+ let(:exception) { RuntimeError.new }
68
+ it { is_expected.to be(true) }
69
+ end
70
+
71
+ context 'subclass of RuntimeError' do
72
+ let(:exception) { Class.new(RuntimeError).new }
73
+ it { is_expected.to be(true) }
74
+ end
75
+ end
76
+
77
+ context 'with whitelist' do
78
+ let(:options) { { limit: 10, retryable_exceptions: [RuntimeError] } }
79
+
80
+ context 'Exception' do
81
+ let(:exception) { Exception.new }
82
+ it { is_expected.to be(false) }
83
+ end
84
+
85
+ context 'RuntimeError' do
86
+ let(:exception) { RuntimeError.new }
87
+ it { is_expected.to be(true) }
88
+ end
89
+
90
+ context 'subclass of RuntimeError' do
91
+ let(:exception) { Class.new(RuntimeError).new }
92
+ it { is_expected.to be(true) }
93
+ end
94
+ end
95
+
96
+ context 'with blacklist' do
97
+ let(:options) { { limit: 10, fatal_exceptions: [RuntimeError] } }
98
+
99
+ context 'Exception' do
100
+ let(:exception) { Exception.new }
101
+ it { is_expected.to be(true) }
102
+ end
103
+
104
+ context 'RuntimeError' do
105
+ let(:exception) { RuntimeError.new }
106
+ it { is_expected.to be(false) }
107
+ end
108
+
109
+ context 'subclass of RuntimeError' do
110
+ let(:exception) { Class.new(RuntimeError).new }
111
+ it { is_expected.to be(false) }
112
+ end
113
+ end
114
+ end
115
+
116
+ describe '#retry_delay' do
117
+ subject { strategy.retry_delay(attempt, exception) }
118
+ let(:exception) { RuntimeError.new }
119
+
120
+ context 'limited retries' do
121
+ let(:options) { { limit: 5 } }
122
+ let(:attempt) { 1 }
123
+
124
+ let(:attempt_3_delay) { strategy.retry_delay(attempt_3, exception) }
125
+ let(:attempt_5_delay) { strategy.retry_delay(attempt_5, exception) }
126
+
127
+ let(:attempt_3) { 3 }
128
+ let(:attempt_5) { 5 }
129
+
130
+ it 'returns value greater than previous for each of the following attempts' do
131
+ expect(subject).to be < attempt_3_delay
132
+ expect(attempt_3_delay).to be < attempt_5_delay
133
+ end
134
+ end
135
+
136
+ context 'unlimited retries' do
137
+ let(:options) { { limit: nil, unlimited_retries: true } }
138
+ let(:attempt) { 1000 }
139
+
140
+ specify { expect { subject }.to_not raise_error }
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActiveJob::Retry::ExponentialOptionsValidator do
4
+ let(:validator) { described_class.new(options) }
5
+ subject(:validate!) { -> { validator.validate! } }
6
+
7
+ context 'valid options' do
8
+ context 'unlimited retries' do
9
+ let(:options) { { limit: nil, unlimited_retries: true } }
10
+ it { is_expected.to_not raise_error }
11
+ end
12
+
13
+ context 'no retries' do
14
+ let(:options) { { limit: 0 } }
15
+ it { is_expected.to_not raise_error }
16
+ end
17
+
18
+ context 'some retries' do
19
+ let(:options) { { limit: 3 } }
20
+ it { is_expected.to_not raise_error }
21
+ end
22
+
23
+ context 'fatal_exceptions' do
24
+ let(:options) { { fatal_exceptions: [RuntimeError] } }
25
+ it { is_expected.to_not raise_error }
26
+ end
27
+
28
+ context 'retryable_exceptions' do
29
+ let(:options) { { retryable_exceptions: [StandardError, NoMethodError] } }
30
+ it { is_expected.to_not raise_error }
31
+ end
32
+
33
+ context 'multiple options' do
34
+ let(:options) { { limit: 3, retryable_exceptions: [RuntimeError] } }
35
+
36
+ it { is_expected.to_not raise_error }
37
+ end
38
+ end
39
+
40
+ context 'invalid options' do
41
+ context 'bad limit' do
42
+ let(:options) { { limit: -1 } }
43
+ it { is_expected.to raise_error(ActiveJob::Retry::InvalidConfigurationError) }
44
+ end
45
+
46
+ context 'accidental infinite limit' do
47
+ let(:options) { { limit: nil } }
48
+ it { is_expected.to raise_error(ActiveJob::Retry::InvalidConfigurationError) }
49
+ end
50
+
51
+ context 'accidental finite limit' do
52
+ let(:options) { { unlimited_retries: true } }
53
+ it { is_expected.to raise_error(ActiveJob::Retry::InvalidConfigurationError) }
54
+ end
55
+
56
+ context 'delay provided' do
57
+ let(:options) { { delay: 1 } }
58
+ it { is_expected.to raise_error(ActiveJob::Retry::InvalidConfigurationError) }
59
+ end
60
+
61
+ context 'bad fatal_exceptions' do
62
+ let(:options) { { fatal_exceptions: ['StandardError'] } }
63
+ it { is_expected.to raise_error(ActiveJob::Retry::InvalidConfigurationError) }
64
+ end
65
+
66
+ context 'bad retryable_exceptions' do
67
+ let(:options) { { retryable_exceptions: [:runtime] } }
68
+ it { is_expected.to raise_error(ActiveJob::Retry::InvalidConfigurationError) }
69
+ end
70
+
71
+ context 'retry and fatal exceptions together' do
72
+ let(:options) { { fatal_exceptions: [StandardError], retryable_exceptions: [] } }
73
+ it { is_expected.to raise_error(ActiveJob::Retry::InvalidConfigurationError) }
74
+ end
75
+ end
76
+ end
data/spec/retry_spec.rb CHANGED
@@ -43,6 +43,28 @@ RSpec.describe ActiveJob::Retry do
43
43
  end
44
44
  end
45
45
 
46
+ describe '.exponential_retry' do
47
+ it 'sets an ExponentialBackoffStrategy' do
48
+ job.exponential_retry(limit: 10)
49
+ expect(job.backoff_strategy).to be_a(ActiveJob::Retry::ExponentialBackoffStrategy)
50
+ end
51
+
52
+ context 'invalid options' do
53
+ let(:options) { { limit: -2 } }
54
+ let(:options_with_delay) { { limit: 2, delay: 3 } }
55
+
56
+ specify do
57
+ expect { job.exponential_retry(options) }.
58
+ to raise_error(ActiveJob::Retry::InvalidConfigurationError)
59
+ end
60
+
61
+ specify do
62
+ expect { job.exponential_retry(options_with_delay) }.
63
+ to raise_error(ActiveJob::Retry::InvalidConfigurationError)
64
+ end
65
+ end
66
+ end
67
+
46
68
  describe '.retry_with' do
47
69
  it 'rejects invalid backoff strategies' do
48
70
  expect { job.retry_with(Object.new) }.
metadata CHANGED
@@ -1,97 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activejob-retry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Isaac Seymour
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-22 00:00:00.000000000 Z
11
+ date: 2015-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '4.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '4.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '4.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '10.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '10.3'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec-its
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rubocop
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  description: |2
@@ -110,10 +110,10 @@ executables: []
110
110
  extensions: []
111
111
  extra_rdoc_files: []
112
112
  files:
113
- - .gitignore
114
- - .rspec
115
- - .rubocop.yml
116
- - .travis.yml
113
+ - ".gitignore"
114
+ - ".rspec"
115
+ - ".rubocop.yml"
116
+ - ".travis.yml"
117
117
  - CHANGELOG.md
118
118
  - Gemfile
119
119
  - Gemfile.lock
@@ -126,12 +126,16 @@ files:
126
126
  - lib/active_job/retry/constant_options_validator.rb
127
127
  - lib/active_job/retry/deserialize_monkey_patch.rb
128
128
  - lib/active_job/retry/errors.rb
129
+ - lib/active_job/retry/exponential_backoff_strategy.rb
130
+ - lib/active_job/retry/exponential_options_validator.rb
129
131
  - lib/active_job/retry/variable_backoff_strategy.rb
130
132
  - lib/active_job/retry/variable_options_validator.rb
131
133
  - lib/active_job/retry/version.rb
132
134
  - lib/activejob/retry.rb
133
135
  - spec/retry/constant_backoff_strategy_spec.rb
134
136
  - spec/retry/constant_options_validator_spec.rb
137
+ - spec/retry/exponential_backoff_strategy_spec.rb
138
+ - spec/retry/exponential_options_validator_spec.rb
135
139
  - spec/retry/variable_backoff_strategy_spec.rb
136
140
  - spec/retry/variable_options_validator_spec.rb
137
141
  - spec/retry_spec.rb
@@ -189,12 +193,12 @@ require_paths:
189
193
  - lib
190
194
  required_ruby_version: !ruby/object:Gem::Requirement
191
195
  requirements:
192
- - - '>='
196
+ - - ">="
193
197
  - !ruby/object:Gem::Version
194
198
  version: '0'
195
199
  required_rubygems_version: !ruby/object:Gem::Requirement
196
200
  requirements:
197
- - - '>='
201
+ - - ">="
198
202
  - !ruby/object:Gem::Version
199
203
  version: '0'
200
204
  requirements: []