activejob-retry 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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: []