activejob-retry 0.6.2 → 0.6.3

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: bb158e4b3bbb44f1212648e777ca1701f5dab910
4
- data.tar.gz: a93e0a2c4949b1a3e87024ada9508e0347f3ec84
3
+ metadata.gz: 4fbf3f8e2eee97ef30a65fdc9f627acb6fd9c271
4
+ data.tar.gz: 24c084bf1714043588bcd7643a39eabfdfe71d38
5
5
  SHA512:
6
- metadata.gz: 5f08d5d8a6466b54a798e988c50a8e27d6ab1c9273e5910e0c11b15a38facae0b7f75c3a5d5970b51178661f0a5e13ec624b36ffee97d1c64eae93c4946132f5
7
- data.tar.gz: feef5212819586918cb91968980974c84a5e142ba94ace753d8cac05eb04e98fc3ebed1679c6582283791d8fe05ec44cea85d134e65ed75a42eb7f2a8c328e03
6
+ metadata.gz: c62d03830fe93de1de6f04ae1e712c9098dd2e0ed029898faafad283406b8766f00a7f6b69c2de323176038149f48ca45a6759486f6f3109cfd9efca083b5ae3
7
+ data.tar.gz: '094302d4b6466df850e38a94af520c64d8141284bcde467ba66e71149a8113bd3527a0d9334b9dd95562b48895989e958a0a0a032afc8ca3129b9bf83c51d72d'
@@ -12,9 +12,6 @@ LineLength:
12
12
  Style/SignalException:
13
13
  EnforcedStyle: 'only_raise'
14
14
 
15
- Metrics/MethodLength:
16
- CountComments: false
17
-
18
15
  Style/Documentation:
19
16
  Enabled: false
20
17
 
@@ -23,3 +20,12 @@ Style/DotPosition:
23
20
 
24
21
  Style/GuardClause:
25
22
  Enabled: false
23
+
24
+ Metrics/MethodLength:
25
+ CountComments: false
26
+
27
+ Metrics/BlockLength:
28
+ CountComments: false
29
+ Exclude:
30
+ - Rakefile
31
+ - spec/**/*
@@ -6,21 +6,26 @@ language: ruby
6
6
  matrix:
7
7
  exclude:
8
8
  # Rails 5.0 dropped support for Ruby <2.2
9
- - rvm: 2.0
10
- gemfile: Gemfile.activejob50
11
9
  - rvm: 2.1
12
10
  gemfile: Gemfile.activejob50
11
+ # Rails 4-2-stable supports Ruby 2.4, but the released version doesn't. Ignore for now.
12
+ - rvm: 2.4.0
13
+ gemfile: Gemfile.activejob42
13
14
 
14
15
  rvm:
15
- - 2.0
16
16
  - 2.1
17
17
  - 2.2.2
18
- - 2.3.1
18
+ - 2.3.3
19
+ - 2.4.0
19
20
 
20
21
  gemfile:
21
22
  - Gemfile.activejob42
22
23
  - Gemfile.activejob50
23
24
 
25
+ before_install:
26
+ - gem update --system
27
+ - gem install bundler
28
+
24
29
  script:
25
30
  - bundle exec rubocop
26
31
  - bundle exec rspec spec
@@ -31,4 +36,4 @@ services:
31
36
  - rabbitmq
32
37
 
33
38
  addons:
34
- postgresql: "9.4"
39
+ postgresql: "9.6"
@@ -1,3 +1,16 @@
1
+ ## 0.6.3 - Feb 9, 2017
2
+
3
+ - Add `callback` option, to be run before each retry, and potentially cancel the retry (by
4
+ [@doits](https://github.com/doits))
5
+
6
+ ## 0.6.2 - Aug 10, 2016
7
+
8
+ - Rails 5 support (by [@isaacseymour](https://github.com/isaacseymour))
9
+
10
+ ## 0.6.1 - Jun 1, 2016
11
+
12
+ - Apply retry settings to subclasses (by [@isaacseymour](https://github.com/isaacseymour))
13
+
1
14
  ## 0.6.0 - May 18, 2016
2
15
 
3
16
  - Change API usage to make improper use harder (by [@isaacseymour](https://github.com/isaacseymour))
@@ -17,4 +17,7 @@ group :test, :integration do
17
17
  gem 'sqlite3'
18
18
  gem 'pg'
19
19
  gem 'rails', '~> 4.2'
20
+
21
+ # This is annoyingly required to make rubocop install
22
+ gem 'rake'
20
23
  end
@@ -19,4 +19,7 @@ group :test, :integration do
19
19
  gem 'rails', '~> 5.0'
20
20
 
21
21
  gem 'pry'
22
+
23
+ # This is annoyingly required to make rubocop install
24
+ gem 'rake'
22
25
  end
data/README.md CHANGED
@@ -65,7 +65,6 @@ if the exception is not going to be retried, or has failed the final retry.
65
65
  | `fatal_exceptions` | `[]` | Same as for [constant](#constant-options).
66
66
 
67
67
  #### variable options
68
-
69
68
  | Option | Default | Description |
70
69
  |:---------------------- |:------- |:------------- |
71
70
  | `delays` | | __required__ An array of delays between attempts in seconds. The first attempt will occur whenever you originally enqueued the job to happen.
@@ -74,6 +73,42 @@ if the exception is not going to be retried, or has failed the final retry.
74
73
  | `retryable_exceptions` | `nil` | Same as for [constant](#constant-options).
75
74
  | `fatal_exceptions` | `[]` | Same as for [constant](#constant-options).
76
75
 
76
+ ## Callback
77
+
78
+ All strategies support a `callback` option:
79
+
80
+ ```ruby
81
+ class ProcessWebhook < ActiveJob::Base
82
+ include ActiveJob::Retry.new(
83
+ strategy: :exponential, limit: 25,
84
+ callback: proc do |exception, delay|
85
+ # will be run before each retry
86
+ end
87
+ )
88
+ end
89
+ ```
90
+
91
+ `callback` must be a `proc` and is run before each retry. It receives the
92
+ exception and delay before the next retry as arguments. It is evaluated on
93
+ instance level, so you have access to all instance variables and methods (for
94
+ example `retry_attempt`) of your job.
95
+
96
+ If the callback returns `:halt`, retry chain is halted and no further retries
97
+ will be made:
98
+
99
+ ```ruby
100
+ class ProcessWebhook < ActiveJob::Base
101
+ include ActiveJob::Retry.new(
102
+ strategy: :exponential, limit: 25,
103
+ callback: proc do |exception, delay|
104
+ if some_condition
105
+ :halt # this will halt the retry chain
106
+ end
107
+ end
108
+ )
109
+ end
110
+ ```
111
+
77
112
  ## Supported backends
78
113
 
79
114
  Any queue adapter which supports delayed enqueuing (i.e. the `enqueue_at`
@@ -121,9 +156,8 @@ ActiveJob jobs.
121
156
  Supported Versions
122
157
  ------------------
123
158
 
124
- Rails 4.2 and 5.0 are supported, on all versions of MRI which they support, except
125
- Ruby 1.9.3. Other Ruby runtimes (e.g. JRuby, Rubinius) probably work, but are not
126
- tested in Travis CI.
159
+ Rails 4.2 and 5.0 are supported, Ruby 2.1+. Other Ruby runtimes (e.g. JRuby,
160
+ Rubinius) probably work, but are not tested in Travis CI.
127
161
 
128
162
  Contributing
129
163
  ------------
@@ -32,15 +32,12 @@ module ActiveJob
32
32
  #################
33
33
  # Configuration #
34
34
  #################
35
- def initialize(strategy: nil, **options)
35
+ def initialize(strategy: nil, callback: nil, **options)
36
36
  check_adapter!
37
37
  @backoff_strategy = choose_strategy(strategy, options)
38
+ @retry_callback = callback
38
39
 
39
- unless backoff_strategy_valid?
40
- raise InvalidConfigurationError,
41
- 'Backoff strategies must define `should_retry?(attempt, exception)`, ' \
42
- 'and `retry_delay(attempt, exception)`.'
43
- end
40
+ validate_params
44
41
  end
45
42
 
46
43
  def included(base)
@@ -52,11 +49,12 @@ module ActiveJob
52
49
  define_retry_attempt_tracking(base)
53
50
  define_retry_method(base)
54
51
  define_retry_logic(base)
52
+ define_retry_callback(base)
55
53
  end
56
54
 
57
55
  private
58
56
 
59
- attr_reader :backoff_strategy
57
+ attr_reader :backoff_strategy, :retry_callback
60
58
 
61
59
  def define_backoff_strategy(klass)
62
60
  klass.instance_variable_set(:@backoff_strategy, @backoff_strategy)
@@ -80,6 +78,11 @@ module ActiveJob
80
78
  klass.instance_eval do
81
79
  define_method :internal_retry do |exception|
82
80
  this_delay = self.class.backoff_strategy.retry_delay(retry_attempt, exception)
81
+
82
+ cb = self.class.retry_callback &&
83
+ instance_exec(exception, this_delay, &self.class.retry_callback)
84
+ return if cb == :halt
85
+
83
86
  # TODO: This breaks DelayedJob and Resque for some weird ActiveSupport reason.
84
87
  # logger.info("Retrying (attempt #{retry_attempt + 1}, waiting #{this_delay}s)")
85
88
  @retry_attempt += 1
@@ -103,6 +106,11 @@ module ActiveJob
103
106
  end
104
107
  end
105
108
 
109
+ def define_retry_callback(klass)
110
+ klass.instance_variable_set(:@retry_callback, @retry_callback)
111
+ klass.define_singleton_method(:retry_callback) { @retry_callback }
112
+ end
113
+
106
114
  def check_adapter!
107
115
  adapter = ActiveJob::Base.queue_adapter
108
116
  adapter_name =
@@ -117,6 +125,18 @@ module ActiveJob
117
125
  end
118
126
  end
119
127
 
128
+ def validate_params
129
+ if retry_callback && !retry_callback.is_a?(Proc)
130
+ raise InvalidConfigurationError, 'Callback must be a `Proc`'
131
+ end
132
+
133
+ unless backoff_strategy_valid?
134
+ raise InvalidConfigurationError,
135
+ 'Backoff strategies must define `should_retry?(attempt, exception)`, ' \
136
+ 'and `retry_delay(attempt, exception)`.'
137
+ end
138
+ end
139
+
120
140
  def backoff_strategy_valid?
121
141
  backoff_strategy.respond_to?(:should_retry?) &&
122
142
  backoff_strategy.respond_to?(:retry_delay) &&
@@ -29,7 +29,7 @@ module ActiveJob
29
29
  # Limit must be an integer >= 0, or nil
30
30
  def validate_limit_numericality!
31
31
  return unless options[:limit]
32
- return if options[:limit].is_a?(Fixnum) && options[:limit] >= 0
32
+ return if options[:limit].is_a?(Integer) && options[:limit] >= 0
33
33
 
34
34
  raise InvalidConfigurationError,
35
35
  'Limit must be an integer >= 0, or nil for unlimited retries'
@@ -29,7 +29,7 @@ module ActiveJob
29
29
  # Limit must be an integer >= 0, or nil
30
30
  def validate_limit_numericality!
31
31
  return unless options[:limit]
32
- return if options[:limit].is_a?(Fixnum) && options[:limit] >= 0
32
+ return if options[:limit].is_a?(Integer) && options[:limit] >= 0
33
33
 
34
34
  raise InvalidConfigurationError,
35
35
  'Limit must be an integer >= 0, or nil for unlimited retries'
@@ -1,5 +1,5 @@
1
1
  module ActiveJob
2
2
  class Retry < Module
3
- VERSION = '0.6.2'.freeze
3
+ VERSION = '0.6.3'.freeze
4
4
  end
5
5
  end
@@ -295,4 +295,56 @@ RSpec.describe ActiveJob::Retry do
295
295
  end
296
296
  end
297
297
  end
298
+
299
+ describe 'retry callback' do
300
+ let(:retry_instance) do
301
+ described_class.new(strategy: :constant, callback: callback, **options)
302
+ end
303
+ let(:callback_double) { double(call: nil) }
304
+ let(:callback) { callback_double.method(:call).to_proc }
305
+ let(:instance) { job.new }
306
+ subject(:perform) { instance.perform_now }
307
+
308
+ context 'invalid options' do
309
+ let(:callback) { 'not a proc' }
310
+
311
+ specify do
312
+ expect { retry_instance }.
313
+ to raise_error(ActiveJob::Retry::InvalidConfigurationError)
314
+ end
315
+ end
316
+
317
+ context 'when the job should be retried' do
318
+ before do
319
+ expect(job.backoff_strategy).to receive(:should_retry?).
320
+ with(1, instance_of(RuntimeError)).
321
+ and_return(true)
322
+ end
323
+
324
+ it 'executes callback proc on retry' do
325
+ expect(callback_double).to receive(:call)
326
+ perform
327
+ end
328
+
329
+ context 'with callback returning :halt' do
330
+ let(:callback) { proc { :halt } }
331
+
332
+ it 'it does not retry the job' do
333
+ expect(instance).not_to receive(:retry_job)
334
+
335
+ perform
336
+ end
337
+ end
338
+
339
+ context 'with callback not returning :halt' do
340
+ let(:callback) { proc { 'not halt' } }
341
+
342
+ it 'it retries the job' do
343
+ expect(instance).to receive(:retry_job)
344
+
345
+ perform
346
+ end
347
+ end
348
+ end
349
+ end
298
350
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activejob-retry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Isaac Seymour
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-10 00:00:00.000000000 Z
11
+ date: 2017-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -200,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
200
  version: '0'
201
201
  requirements: []
202
202
  rubyforge_project:
203
- rubygems_version: 2.5.1
203
+ rubygems_version: 2.6.10
204
204
  signing_key:
205
205
  specification_version: 4
206
206
  summary: Automatic retry functionality for ActiveJob.