activejob-retry 0.6.2 → 0.6.3

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: 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.