activejob-retry 0.5.1 → 0.6.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 +4 -4
- data/.travis.yml +1 -3
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +116 -126
- data/README.md +24 -22
- data/Rakefile +10 -9
- data/activejob-retry.gemspec +1 -1
- data/lib/active_job/retry.rb +75 -65
- data/lib/active_job/retry/constant_backoff_strategy.rb +1 -1
- data/lib/active_job/retry/constant_options_validator.rb +1 -1
- data/lib/active_job/retry/errors.rb +1 -1
- data/lib/active_job/retry/exponential_backoff_strategy.rb +1 -1
- data/lib/active_job/retry/exponential_options_validator.rb +1 -1
- data/lib/active_job/retry/variable_backoff_strategy.rb +1 -1
- data/lib/active_job/retry/variable_options_validator.rb +1 -1
- data/lib/active_job/retry/version.rb +2 -2
- data/spec/retry_spec.rb +41 -31
- data/spec/spec_helper.rb +1 -1
- data/test/jobs/callback_job.rb +1 -1
- data/test/jobs/gid_job.rb +1 -1
- data/test/jobs/hello_job.rb +1 -1
- data/test/jobs/logging_job.rb +1 -1
- data/test/jobs/nested_job.rb +1 -1
- data/test/jobs/rescue_job.rb +1 -2
- data/test/support/integration/dummy_app_template.rb +1 -2
- metadata +4 -5
- data/test/cases/argument_serialization_test.rb +0 -84
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d4ed8260c84b5c95a405c8cadb2a2b0e93ba5070
|
|
4
|
+
data.tar.gz: 1b7d2e89e1843ee73c6461374397a5e0450637c5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c03c64268ed4f9a40a0d35b178e96550d24ad6b03b7cc65a1e43440845d6ff39f78fda571e5e06dcc6b83b6a736d97c9449768abca698d2bfd20830cd03d99a
|
|
7
|
+
data.tar.gz: 64233f0b5a15269e040f5f9b306ab58cb27f437dd93fe610dc68f880b28f1758e878674aaa547479b9faac12c74820bec73714891afd743f5690f1c6db78ce5f
|
data/.travis.yml
CHANGED
|
@@ -9,10 +9,9 @@ matrix:
|
|
|
9
9
|
- rvm: rbx-2
|
|
10
10
|
|
|
11
11
|
rvm:
|
|
12
|
-
- 1.9.3
|
|
13
|
-
- 2.0.0
|
|
14
12
|
- 2.1
|
|
15
13
|
- 2.2
|
|
14
|
+
- 2.3.1
|
|
16
15
|
- jruby
|
|
17
16
|
- rbx-2
|
|
18
17
|
|
|
@@ -20,7 +19,6 @@ script:
|
|
|
20
19
|
- bundle exec rubocop
|
|
21
20
|
- bundle exec rspec spec
|
|
22
21
|
- bundle exec rake test
|
|
23
|
-
- bundle exec rake test:integration
|
|
24
22
|
|
|
25
23
|
services:
|
|
26
24
|
- redis
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 0.6.0 - May 18, 2016
|
|
2
|
+
|
|
3
|
+
- Change API usage to make improper use harder (by [@isaacseymour](https://github.com/isaacseymour))
|
|
4
|
+
|
|
1
5
|
## 0.5.1 - October 28, 2015
|
|
2
6
|
|
|
3
7
|
- Stop warning about QueueClassic - it supports delayed execution from 3.1+ (by [@senny](https://github.com/senny))
|
data/Gemfile.lock
CHANGED
|
@@ -1,189 +1,179 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
activejob-retry (0.
|
|
4
|
+
activejob-retry (0.6.0)
|
|
5
5
|
activejob (>= 4.2)
|
|
6
6
|
activesupport (>= 4.2)
|
|
7
7
|
|
|
8
8
|
GEM
|
|
9
9
|
remote: https://rubygems.org/
|
|
10
10
|
specs:
|
|
11
|
-
actionmailer (4.2.
|
|
12
|
-
actionpack (= 4.2.
|
|
13
|
-
actionview (= 4.2.
|
|
14
|
-
activejob (= 4.2.
|
|
11
|
+
actionmailer (4.2.6)
|
|
12
|
+
actionpack (= 4.2.6)
|
|
13
|
+
actionview (= 4.2.6)
|
|
14
|
+
activejob (= 4.2.6)
|
|
15
15
|
mail (~> 2.5, >= 2.5.4)
|
|
16
16
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
|
17
|
-
actionpack (4.2.
|
|
18
|
-
actionview (= 4.2.
|
|
19
|
-
activesupport (= 4.2.
|
|
20
|
-
rack (~> 1.6
|
|
17
|
+
actionpack (4.2.6)
|
|
18
|
+
actionview (= 4.2.6)
|
|
19
|
+
activesupport (= 4.2.6)
|
|
20
|
+
rack (~> 1.6)
|
|
21
21
|
rack-test (~> 0.6.2)
|
|
22
22
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
|
23
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.
|
|
24
|
-
actionview (4.2.
|
|
25
|
-
activesupport (= 4.2.
|
|
23
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
24
|
+
actionview (4.2.6)
|
|
25
|
+
activesupport (= 4.2.6)
|
|
26
26
|
builder (~> 3.1)
|
|
27
27
|
erubis (~> 2.7.0)
|
|
28
28
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
|
29
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.
|
|
30
|
-
activejob (4.2.
|
|
31
|
-
activesupport (= 4.2.
|
|
29
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
30
|
+
activejob (4.2.6)
|
|
31
|
+
activesupport (= 4.2.6)
|
|
32
32
|
globalid (>= 0.3.0)
|
|
33
|
-
activemodel (4.2.
|
|
34
|
-
activesupport (= 4.2.
|
|
33
|
+
activemodel (4.2.6)
|
|
34
|
+
activesupport (= 4.2.6)
|
|
35
35
|
builder (~> 3.1)
|
|
36
|
-
activerecord (4.2.
|
|
37
|
-
activemodel (= 4.2.
|
|
38
|
-
activesupport (= 4.2.
|
|
36
|
+
activerecord (4.2.6)
|
|
37
|
+
activemodel (= 4.2.6)
|
|
38
|
+
activesupport (= 4.2.6)
|
|
39
39
|
arel (~> 6.0)
|
|
40
|
-
activesupport (4.2.
|
|
40
|
+
activesupport (4.2.6)
|
|
41
41
|
i18n (~> 0.7)
|
|
42
42
|
json (~> 1.7, >= 1.7.7)
|
|
43
43
|
minitest (~> 5.1)
|
|
44
44
|
thread_safe (~> 0.3, >= 0.3.4)
|
|
45
45
|
tzinfo (~> 1.1)
|
|
46
|
-
arel (6.0.
|
|
47
|
-
ast (2.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
dante (~> 0.1.5)
|
|
53
|
-
beaneater (0.3.3)
|
|
46
|
+
arel (6.0.3)
|
|
47
|
+
ast (2.2.0)
|
|
48
|
+
backburner (1.3.0)
|
|
49
|
+
beaneater (~> 1.0)
|
|
50
|
+
dante (> 0.1.5)
|
|
51
|
+
beaneater (1.0.0)
|
|
54
52
|
builder (3.2.2)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
delayed_job (>= 3.0, < 4.1)
|
|
53
|
+
concurrent-ruby (1.0.2)
|
|
54
|
+
connection_pool (2.2.0)
|
|
55
|
+
dante (0.2.0)
|
|
56
|
+
delayed_job (4.1.2)
|
|
57
|
+
activesupport (>= 3.0, < 5.1)
|
|
58
|
+
delayed_job_active_record (4.1.1)
|
|
59
|
+
activerecord (>= 3.0, < 5.1)
|
|
60
|
+
delayed_job (>= 3.0, < 5)
|
|
64
61
|
diff-lcs (1.2.5)
|
|
65
62
|
erubis (2.7.0)
|
|
66
|
-
globalid (0.3.
|
|
63
|
+
globalid (0.3.6)
|
|
67
64
|
activesupport (>= 4.1.0)
|
|
68
|
-
hike (1.2.3)
|
|
69
|
-
hitimes (1.2.2)
|
|
70
65
|
i18n (0.7.0)
|
|
71
|
-
json (1.8.
|
|
72
|
-
loofah (2.0.
|
|
66
|
+
json (1.8.3)
|
|
67
|
+
loofah (2.0.3)
|
|
73
68
|
nokogiri (>= 1.5.9)
|
|
74
|
-
mail (2.6.
|
|
75
|
-
mime-types (>= 1.16, <
|
|
76
|
-
mime-types (
|
|
77
|
-
|
|
78
|
-
|
|
69
|
+
mail (2.6.4)
|
|
70
|
+
mime-types (>= 1.16, < 4)
|
|
71
|
+
mime-types (3.0)
|
|
72
|
+
mime-types-data (~> 3.2015)
|
|
73
|
+
mime-types-data (3.2016.0221)
|
|
74
|
+
mini_portile2 (2.0.0)
|
|
75
|
+
minitest (5.9.0)
|
|
79
76
|
mono_logger (1.1.0)
|
|
80
|
-
multi_json (1.
|
|
81
|
-
nokogiri (1.6.
|
|
82
|
-
|
|
83
|
-
parser (2.
|
|
84
|
-
ast (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
rack (1.6.0)
|
|
77
|
+
multi_json (1.12.0)
|
|
78
|
+
nokogiri (1.6.7.2)
|
|
79
|
+
mini_portile2 (~> 2.0.0.rc2)
|
|
80
|
+
parser (2.3.1.0)
|
|
81
|
+
ast (~> 2.2)
|
|
82
|
+
pg (0.18.4)
|
|
83
|
+
powerpack (0.1.1)
|
|
84
|
+
que (0.11.5)
|
|
85
|
+
rack (1.6.4)
|
|
90
86
|
rack-protection (1.5.3)
|
|
91
87
|
rack
|
|
92
|
-
rack-test (0.6.
|
|
88
|
+
rack-test (0.6.3)
|
|
93
89
|
rack (>= 1.0)
|
|
94
|
-
rails (4.2.
|
|
95
|
-
actionmailer (= 4.2.
|
|
96
|
-
actionpack (= 4.2.
|
|
97
|
-
actionview (= 4.2.
|
|
98
|
-
activejob (= 4.2.
|
|
99
|
-
activemodel (= 4.2.
|
|
100
|
-
activerecord (= 4.2.
|
|
101
|
-
activesupport (= 4.2.
|
|
90
|
+
rails (4.2.6)
|
|
91
|
+
actionmailer (= 4.2.6)
|
|
92
|
+
actionpack (= 4.2.6)
|
|
93
|
+
actionview (= 4.2.6)
|
|
94
|
+
activejob (= 4.2.6)
|
|
95
|
+
activemodel (= 4.2.6)
|
|
96
|
+
activerecord (= 4.2.6)
|
|
97
|
+
activesupport (= 4.2.6)
|
|
102
98
|
bundler (>= 1.3.0, < 2.0)
|
|
103
|
-
railties (= 4.2.
|
|
99
|
+
railties (= 4.2.6)
|
|
104
100
|
sprockets-rails
|
|
105
101
|
rails-deprecated_sanitizer (1.0.3)
|
|
106
102
|
activesupport (>= 4.2.0.alpha)
|
|
107
|
-
rails-dom-testing (1.0.
|
|
103
|
+
rails-dom-testing (1.0.7)
|
|
108
104
|
activesupport (>= 4.2.0.beta, < 5.0)
|
|
109
105
|
nokogiri (~> 1.6.0)
|
|
110
106
|
rails-deprecated_sanitizer (>= 1.0.1)
|
|
111
|
-
rails-html-sanitizer (1.0.
|
|
107
|
+
rails-html-sanitizer (1.0.3)
|
|
112
108
|
loofah (~> 2.0)
|
|
113
|
-
railties (4.2.
|
|
114
|
-
actionpack (= 4.2.
|
|
115
|
-
activesupport (= 4.2.
|
|
109
|
+
railties (4.2.6)
|
|
110
|
+
actionpack (= 4.2.6)
|
|
111
|
+
activesupport (= 4.2.6)
|
|
116
112
|
rake (>= 0.8.7)
|
|
117
113
|
thor (>= 0.18.1, < 2.0)
|
|
118
|
-
rainbow (2.
|
|
119
|
-
rake (
|
|
120
|
-
redis (3.
|
|
121
|
-
redis-namespace (1.5.
|
|
114
|
+
rainbow (2.1.0)
|
|
115
|
+
rake (11.1.2)
|
|
116
|
+
redis (3.3.0)
|
|
117
|
+
redis-namespace (1.5.2)
|
|
122
118
|
redis (~> 3.0, >= 3.0.4)
|
|
123
|
-
resque (1.
|
|
119
|
+
resque (1.26.0)
|
|
124
120
|
mono_logger (~> 1.0)
|
|
125
121
|
multi_json (~> 1.0)
|
|
126
122
|
redis-namespace (~> 1.3)
|
|
127
123
|
sinatra (>= 0.9.2)
|
|
128
124
|
vegas (~> 0.1.2)
|
|
129
|
-
resque-scheduler (4.
|
|
125
|
+
resque-scheduler (4.2.0)
|
|
130
126
|
mono_logger (~> 1.0)
|
|
131
127
|
redis (~> 3.0)
|
|
132
128
|
resque (~> 1.25)
|
|
133
|
-
rufus-scheduler (~> 3.
|
|
134
|
-
rspec (3.
|
|
135
|
-
rspec-core (~> 3.
|
|
136
|
-
rspec-expectations (~> 3.
|
|
137
|
-
rspec-mocks (~> 3.
|
|
138
|
-
rspec-core (3.
|
|
139
|
-
rspec-support (~> 3.
|
|
140
|
-
rspec-expectations (3.
|
|
129
|
+
rufus-scheduler (~> 3.2)
|
|
130
|
+
rspec (3.4.0)
|
|
131
|
+
rspec-core (~> 3.4.0)
|
|
132
|
+
rspec-expectations (~> 3.4.0)
|
|
133
|
+
rspec-mocks (~> 3.4.0)
|
|
134
|
+
rspec-core (3.4.4)
|
|
135
|
+
rspec-support (~> 3.4.0)
|
|
136
|
+
rspec-expectations (3.4.0)
|
|
141
137
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
142
|
-
rspec-support (~> 3.
|
|
143
|
-
rspec-its (1.
|
|
138
|
+
rspec-support (~> 3.4.0)
|
|
139
|
+
rspec-its (1.2.0)
|
|
144
140
|
rspec-core (>= 3.0.0)
|
|
145
141
|
rspec-expectations (>= 3.0.0)
|
|
146
|
-
rspec-mocks (3.1
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
parser (>= 2.
|
|
152
|
-
powerpack (~> 0.
|
|
142
|
+
rspec-mocks (3.4.1)
|
|
143
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
144
|
+
rspec-support (~> 3.4.0)
|
|
145
|
+
rspec-support (3.4.1)
|
|
146
|
+
rubocop (0.40.0)
|
|
147
|
+
parser (>= 2.3.1.0, < 3.0)
|
|
148
|
+
powerpack (~> 0.1)
|
|
153
149
|
rainbow (>= 1.99.1, < 3.0)
|
|
154
|
-
ruby-progressbar (~> 1.
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
sequel (4.
|
|
159
|
-
sidekiq (
|
|
160
|
-
|
|
161
|
-
connection_pool (>= 2.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
sinatra (1.4.5)
|
|
166
|
-
rack (~> 1.4)
|
|
150
|
+
ruby-progressbar (~> 1.7)
|
|
151
|
+
unicode-display_width (~> 1.0, >= 1.0.1)
|
|
152
|
+
ruby-progressbar (1.8.1)
|
|
153
|
+
rufus-scheduler (3.2.1)
|
|
154
|
+
sequel (4.34.0)
|
|
155
|
+
sidekiq (4.1.2)
|
|
156
|
+
concurrent-ruby (~> 1.0)
|
|
157
|
+
connection_pool (~> 2.2, >= 2.2.0)
|
|
158
|
+
redis (~> 3.2, >= 3.2.1)
|
|
159
|
+
sinatra (1.4.7)
|
|
160
|
+
rack (~> 1.5)
|
|
167
161
|
rack-protection (~> 1.4)
|
|
168
|
-
tilt (
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
activesupport (>= 3.0)
|
|
178
|
-
sprockets (>= 2.8, < 4.0)
|
|
179
|
-
sqlite3 (1.3.10)
|
|
162
|
+
tilt (>= 1.3, < 3)
|
|
163
|
+
sprockets (3.6.0)
|
|
164
|
+
concurrent-ruby (~> 1.0)
|
|
165
|
+
rack (> 1, < 3)
|
|
166
|
+
sprockets-rails (3.0.4)
|
|
167
|
+
actionpack (>= 4.0)
|
|
168
|
+
activesupport (>= 4.0)
|
|
169
|
+
sprockets (>= 3.0.0)
|
|
170
|
+
sqlite3 (1.3.11)
|
|
180
171
|
thor (0.19.1)
|
|
181
|
-
thread_safe (0.3.
|
|
182
|
-
tilt (
|
|
183
|
-
timers (4.0.1)
|
|
184
|
-
hitimes
|
|
172
|
+
thread_safe (0.3.5)
|
|
173
|
+
tilt (2.0.4)
|
|
185
174
|
tzinfo (1.2.2)
|
|
186
175
|
thread_safe (~> 0.1)
|
|
176
|
+
unicode-display_width (1.0.5)
|
|
187
177
|
vegas (0.1.11)
|
|
188
178
|
rack (>= 1.0.0)
|
|
189
179
|
|
|
@@ -209,4 +199,4 @@ DEPENDENCIES
|
|
|
209
199
|
sqlite3
|
|
210
200
|
|
|
211
201
|
BUNDLED WITH
|
|
212
|
-
1.
|
|
202
|
+
1.12.3
|
data/README.md
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
ActiveJob::Retry [](https://travis-ci.org/isaacseymour/activejob-retry)
|
|
2
2
|
================
|
|
3
3
|
|
|
4
4
|
**This is an alpha library** in active development, so the API may change.
|
|
5
5
|
|
|
6
|
-
Automatic retry functionality for ActiveJob. Just `include ActiveJob::Retry
|
|
7
|
-
|
|
8
|
-
retry strategy:
|
|
6
|
+
Automatic retry functionality for ActiveJob. Just `include ActiveJob::Retry.new(strategy:
|
|
7
|
+
:something, **options)` in your job class:
|
|
9
8
|
|
|
10
9
|
```ruby
|
|
11
10
|
class ProcessWebhook < ActiveJob::Base
|
|
12
|
-
include ActiveJob::Retry
|
|
13
|
-
|
|
14
11
|
queue_as :webhooks
|
|
15
12
|
|
|
16
13
|
# Constant delay between attempts:
|
|
17
|
-
|
|
14
|
+
include ActiveJob::Retry.new(strategy: :constant,
|
|
15
|
+
limit: 3,
|
|
16
|
+
delay: 5.minutes,
|
|
17
|
+
retryable_exceptions: [TimeoutError, NetworkError])
|
|
18
18
|
|
|
19
19
|
# Or, variable delay between attempts:
|
|
20
|
-
|
|
20
|
+
include ActiveJob::Retry.new(strategy: :variable,
|
|
21
|
+
delays: [1.minute, 5.minutes, 10.minutes, 30.minutes])
|
|
21
22
|
|
|
22
23
|
# Or, exponential delay between attempts:
|
|
23
|
-
|
|
24
|
+
include ActiveJob::Retry.new(strategy: :exponential, limit: 25)
|
|
24
25
|
|
|
25
26
|
# You can also use a custom backoff strategy by passing an object which responds to
|
|
26
27
|
# `should_retry?(attempt, exception)`, and `retry_delay(attempt, exception)`
|
|
@@ -35,7 +36,7 @@ class ProcessWebhook < ActiveJob::Base
|
|
|
35
36
|
end
|
|
36
37
|
end
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
include ActiveJob::Retry.new(strategy: ChaoticBackoffStrategy)
|
|
39
40
|
|
|
40
41
|
def perform(webhook)
|
|
41
42
|
webhook.process!
|
|
@@ -43,10 +44,10 @@ class ProcessWebhook < ActiveJob::Base
|
|
|
43
44
|
end
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
The retry will get executed before any `rescue_from` blocks, which will only get executed
|
|
47
|
+
The retry will get executed **before** any `rescue_from` blocks, which will only get executed
|
|
47
48
|
if the exception is not going to be retried, or has failed the final retry.
|
|
48
49
|
|
|
49
|
-
####
|
|
50
|
+
#### constant options
|
|
50
51
|
| Option | Default | Description |
|
|
51
52
|
|:---------------------- |:------- |:-------------- |
|
|
52
53
|
| `limit` | `1` | Maximum number of times to attempt the job (default: 1).
|
|
@@ -55,40 +56,41 @@ if the exception is not going to be retried, or has failed the final retry.
|
|
|
55
56
|
| `retryable_exceptions` | `nil` | A whitelist of exceptions to retry. When `nil`, all exceptions will result in a retry.
|
|
56
57
|
| `fatal_exceptions` | `[]` | A blacklist of exceptions to not retry (default: []).
|
|
57
58
|
|
|
58
|
-
####
|
|
59
|
+
#### exponential options
|
|
59
60
|
| Option | Default | Description |
|
|
60
61
|
|:---------------------- |:------- |:-------------- |
|
|
61
62
|
| `limit` | `1` | Maximum number of times to attempt the job (default: 1).
|
|
62
63
|
| `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 [
|
|
64
|
-
| `fatal_exceptions` | `[]` | Same as for [
|
|
64
|
+
| `retryable_exceptions` | `nil` | Same as for [constant](#constant-options).
|
|
65
|
+
| `fatal_exceptions` | `[]` | Same as for [constant](#constant-options).
|
|
65
66
|
|
|
66
|
-
####
|
|
67
|
+
#### variable options
|
|
67
68
|
|
|
68
69
|
| Option | Default | Description |
|
|
69
70
|
|:---------------------- |:------- |:------------- |
|
|
70
71
|
| `delays` | | __required__ An array of delays between attempts in seconds. The first attempt will occur whenever you originally enqueued the job to happen.
|
|
71
72
|
| `min_delay_multiplier` | | If supplied, each delay will be multiplied by a random number between this and `max_delay_multiplier`.
|
|
72
73
|
| `max_delay_multiplier` | | The other end of the range for `min_delay_multiplier`. If one is supplied, both must be.
|
|
73
|
-
| `retryable_exceptions` | `nil` | Same as for [
|
|
74
|
-
| `fatal_exceptions` | `[]` | Same as for [
|
|
74
|
+
| `retryable_exceptions` | `nil` | Same as for [constant](#constant-options).
|
|
75
|
+
| `fatal_exceptions` | `[]` | Same as for [constant](#constant-options).
|
|
75
76
|
|
|
76
77
|
## Supported backends
|
|
77
78
|
|
|
78
79
|
Any queue adapter which supports delayed enqueuing (i.e. the `enqueue_at`
|
|
79
|
-
method) will work with ActiveJob::Retry
|
|
80
|
+
method) will work with `ActiveJob::Retry`, however some queue backends have
|
|
80
81
|
automatic retry logic, which should be disabled. The cleanest way to do this is
|
|
81
82
|
to use a `rescue_from` in the jobs for which you're using ActiveJob::Retry, so
|
|
82
83
|
the queue backend never perceives the job as having failed. E.g.:
|
|
83
84
|
|
|
84
85
|
```ruby
|
|
85
86
|
class MyJob < ActiveJob::Base
|
|
86
|
-
include ActiveJob::Retry
|
|
87
|
+
include ActiveJob::Retry.new(strategy: :constant,
|
|
88
|
+
limit: 3,
|
|
89
|
+
delay: 5,
|
|
90
|
+
retryable_exceptions: [TimeoutError, NetworkError])
|
|
87
91
|
|
|
88
92
|
queue_as :some_job
|
|
89
93
|
|
|
90
|
-
constant_retry limit: 3, delay: 5, retryable_exceptions: [TimeoutError, NetworkError]
|
|
91
|
-
|
|
92
94
|
rescue_from(StandardError) { |error| MyErrorService.record(error) }
|
|
93
95
|
|
|
94
96
|
def perform
|
data/Rakefile
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require 'rake/testtask'
|
|
2
2
|
require 'rubygems/package_task'
|
|
3
3
|
|
|
4
|
-
ACTIVEJOB_ADAPTERS = %w(backburner delayed_job que resque sidekiq)
|
|
4
|
+
ACTIVEJOB_ADAPTERS = %w(backburner delayed_job que resque sidekiq).freeze
|
|
5
5
|
|
|
6
6
|
task default: :test
|
|
7
7
|
task test: 'test:default'
|
|
@@ -49,14 +49,15 @@ namespace :test do
|
|
|
49
49
|
|
|
50
50
|
namespace :integration do
|
|
51
51
|
Rake::TestTask.new(
|
|
52
|
-
adapter => ["test:env:#{adapter}", 'test:env:integration']
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
adapter => ["test:env:#{adapter}", 'test:env:integration']
|
|
53
|
+
) do |t|
|
|
54
|
+
t.description = "Run integration tests for #{adapter}"
|
|
55
|
+
t.libs << 'test'
|
|
56
|
+
t.test_files = FileList['test/integration/**/*_test.rb']
|
|
57
|
+
t.verbose = true
|
|
58
|
+
t.warning = true
|
|
59
|
+
t.ruby_opts = ['--dev'] if defined?(JRUBY_VERSION)
|
|
60
|
+
end
|
|
60
61
|
end
|
|
61
62
|
end
|
|
62
63
|
end
|
data/activejob-retry.gemspec
CHANGED
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
|
18
18
|
* Exponential backoff (varying the delay between retries).
|
|
19
19
|
* Light and easy to override retry logic.
|
|
20
20
|
EOL
|
|
21
|
-
s.homepage = '
|
|
21
|
+
s.homepage = 'https://github.com/isaacseymour/activejob-retry'
|
|
22
22
|
s.license = 'MIT'
|
|
23
23
|
|
|
24
24
|
s.has_rdoc = false
|
data/lib/active_job/retry.rb
CHANGED
|
@@ -11,8 +11,17 @@ unless ActiveJob::Base.method_defined?(:deserialize)
|
|
|
11
11
|
require 'active_job/retry/deserialize_monkey_patch'
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
def choose_strategy(strategy, options)
|
|
15
|
+
case strategy
|
|
16
|
+
when :constant then ActiveJob::Retry::ConstantBackoffStrategy.new(options)
|
|
17
|
+
when :variable then ActiveJob::Retry::VariableBackoffStrategy.new(options)
|
|
18
|
+
when :exponential then ActiveJob::Retry::ExponentialBackoffStrategy.new(options)
|
|
19
|
+
else strategy
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
14
23
|
module ActiveJob
|
|
15
|
-
|
|
24
|
+
class Retry < Module
|
|
16
25
|
PROBLEMATIC_ADAPTERS = [
|
|
17
26
|
'ActiveJob::QueueAdapters::InlineAdapter',
|
|
18
27
|
'ActiveJob::QueueAdapters::QuAdapter',
|
|
@@ -20,88 +29,89 @@ module ActiveJob
|
|
|
20
29
|
'ActiveJob::QueueAdapters::SuckerPunchAdapter'
|
|
21
30
|
].freeze
|
|
22
31
|
|
|
23
|
-
def self.included(base)
|
|
24
|
-
if PROBLEMATIC_ADAPTERS.include?(ActiveJob::Base.queue_adapter.name)
|
|
25
|
-
warn("#{ActiveJob::Base.queue_adapter.name} does not support delayed retries, " \
|
|
26
|
-
'so does not work with ActiveJob::Retry. You may experience strange ' \
|
|
27
|
-
'behaviour.')
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
base.extend(ClassMethods)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
32
|
#################
|
|
34
33
|
# Configuration #
|
|
35
34
|
#################
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def variable_retry(options)
|
|
45
|
-
retry_with(VariableBackoffStrategy.new(options))
|
|
35
|
+
def initialize(strategy: nil, **options)
|
|
36
|
+
check_adapter!
|
|
37
|
+
@backoff_strategy = choose_strategy(strategy, options)
|
|
38
|
+
|
|
39
|
+
unless backoff_strategy_valid?
|
|
40
|
+
raise InvalidConfigurationError,
|
|
41
|
+
'Backoff strategies must define `should_retry?(attempt, exception)`, ' \
|
|
42
|
+
'and `retry_delay(attempt, exception)`.'
|
|
46
43
|
end
|
|
44
|
+
end
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
def included(base)
|
|
47
|
+
define_backoff_strategy(base)
|
|
48
|
+
define_retry_attempt_tracking(base)
|
|
49
|
+
define_retry_method(base)
|
|
50
|
+
define_retry_logic(base)
|
|
51
|
+
end
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
unless backoff_strategy_valid?(backoff_strategy)
|
|
54
|
-
raise InvalidConfigurationError,
|
|
55
|
-
'Backoff strategies must define `should_retry?(attempt, exception)`, ' \
|
|
56
|
-
'and `retry_delay(attempt, exception)`.'
|
|
57
|
-
end
|
|
53
|
+
private
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
end
|
|
55
|
+
attr_reader :backoff_strategy
|
|
61
56
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
backoff_strategy.method(:should_retry?).arity == 2 &&
|
|
66
|
-
backoff_strategy.method(:retry_delay).arity == 2
|
|
67
|
-
end
|
|
57
|
+
def define_backoff_strategy(klass)
|
|
58
|
+
klass.instance_variable_set(:@backoff_strategy, @backoff_strategy)
|
|
59
|
+
klass.define_singleton_method(:backoff_strategy) { @backoff_strategy }
|
|
68
60
|
end
|
|
69
61
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
62
|
+
def define_retry_attempt_tracking(klass)
|
|
63
|
+
klass.instance_eval do
|
|
64
|
+
define_method(:serialize) do |*args|
|
|
65
|
+
super(*args).merge('retry_attempt' => retry_attempt)
|
|
66
|
+
end
|
|
67
|
+
define_method :deserialize do |job_data|
|
|
68
|
+
super(job_data)
|
|
69
|
+
@retry_attempt = job_data['retry_attempt']
|
|
70
|
+
end
|
|
71
|
+
define_method(:retry_attempt) { @retry_attempt ||= 1 }
|
|
72
|
+
end
|
|
76
73
|
end
|
|
77
74
|
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
def define_retry_method(klass)
|
|
76
|
+
klass.instance_eval do
|
|
77
|
+
define_method :internal_retry do |exception|
|
|
78
|
+
this_delay = self.class.backoff_strategy.retry_delay(retry_attempt, exception)
|
|
79
|
+
# TODO: This breaks DelayedJob and Resque for some weird ActiveSupport reason.
|
|
80
|
+
# logger.info("Retrying (attempt #{retry_attempt + 1}, waiting #{this_delay}s)")
|
|
81
|
+
@retry_attempt += 1
|
|
82
|
+
retry_job(wait: this_delay)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
81
85
|
end
|
|
82
86
|
|
|
83
|
-
def
|
|
84
|
-
|
|
87
|
+
def define_retry_logic(klass)
|
|
88
|
+
klass.instance_eval do
|
|
89
|
+
# Override `rescue_with_handler` to make sure our catch is before callbacks,
|
|
90
|
+
# so `rescue_from`s will only be run after any retry attempts have been exhausted.
|
|
91
|
+
define_method :rescue_with_handler do |exception|
|
|
92
|
+
if self.class.backoff_strategy.should_retry?(retry_attempt, exception)
|
|
93
|
+
internal_retry(exception)
|
|
94
|
+
return true # Exception has been handled
|
|
95
|
+
else
|
|
96
|
+
return super(exception)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
85
100
|
end
|
|
86
101
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# so `rescue_from`s will only be run after any retry attempts have been exhausted.
|
|
93
|
-
def rescue_with_handler(exception)
|
|
94
|
-
unless self.class.backoff_strategy.should_retry?(retry_attempt, exception)
|
|
95
|
-
return super
|
|
102
|
+
def check_adapter!
|
|
103
|
+
if PROBLEMATIC_ADAPTERS.include?(ActiveJob::Base.queue_adapter.name)
|
|
104
|
+
warn("#{ActiveJob::Base.queue_adapter.name} does not support delayed retries, " \
|
|
105
|
+
'so does not work with ActiveJob::Retry. You may experience strange ' \
|
|
106
|
+
'behaviour.')
|
|
96
107
|
end
|
|
108
|
+
end
|
|
97
109
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
true # Exception has been handled
|
|
110
|
+
def backoff_strategy_valid?
|
|
111
|
+
backoff_strategy.respond_to?(:should_retry?) &&
|
|
112
|
+
backoff_strategy.respond_to?(:retry_delay) &&
|
|
113
|
+
backoff_strategy.method(:should_retry?).arity == 2 &&
|
|
114
|
+
backoff_strategy.method(:retry_delay).arity == 2
|
|
105
115
|
end
|
|
106
116
|
end
|
|
107
117
|
end
|
|
@@ -2,7 +2,7 @@ require 'active_job/retry/constant_backoff_strategy'
|
|
|
2
2
|
require 'active_job/retry/variable_options_validator'
|
|
3
3
|
|
|
4
4
|
module ActiveJob
|
|
5
|
-
|
|
5
|
+
class Retry < Module
|
|
6
6
|
class VariableBackoffStrategy < ConstantBackoffStrategy
|
|
7
7
|
def initialize(options)
|
|
8
8
|
super(options)
|
data/spec/retry_spec.rb
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
RSpec.describe ActiveJob::Retry do
|
|
4
|
-
|
|
4
|
+
let(:strategy) { :constant }
|
|
5
|
+
let(:options) { {} }
|
|
6
|
+
let(:retry_instance) { described_class.new(strategy: strategy, **options) }
|
|
7
|
+
let(:job) do
|
|
5
8
|
Class.new(ActiveJob::Base) do
|
|
6
|
-
include ActiveJob::Retry
|
|
7
|
-
|
|
8
9
|
def perform(*_args)
|
|
9
10
|
raise RuntimeError
|
|
10
11
|
end
|
|
11
|
-
end
|
|
12
|
+
end.include(retry_instance)
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
describe '.constant_retry' do
|
|
16
|
+
let(:strategy) { :constant }
|
|
17
|
+
let(:options) { { limit: 10, delay: 5 } }
|
|
18
|
+
|
|
15
19
|
it 'sets a ConstantBackoffStrategy' do
|
|
16
|
-
job.constant_retry(limit: 10, delay: 5)
|
|
17
20
|
expect(job.backoff_strategy).to be_a(ActiveJob::Retry::ConstantBackoffStrategy)
|
|
18
21
|
end
|
|
19
22
|
|
|
@@ -21,15 +24,17 @@ RSpec.describe ActiveJob::Retry do
|
|
|
21
24
|
let(:options) { { limit: -2 } }
|
|
22
25
|
|
|
23
26
|
specify do
|
|
24
|
-
expect {
|
|
27
|
+
expect { retry_instance }.
|
|
25
28
|
to raise_error(ActiveJob::Retry::InvalidConfigurationError)
|
|
26
29
|
end
|
|
27
30
|
end
|
|
28
31
|
end
|
|
29
32
|
|
|
30
33
|
describe '.variable_retry' do
|
|
34
|
+
let(:strategy) { :variable }
|
|
35
|
+
let(:options) { { delays: [0, 5, 10, 60, 200] } }
|
|
36
|
+
|
|
31
37
|
it 'sets a VariableBackoffStrategy' do
|
|
32
|
-
job.variable_retry(delays: [0, 5, 10, 60, 200])
|
|
33
38
|
expect(job.backoff_strategy).to be_a(ActiveJob::Retry::VariableBackoffStrategy)
|
|
34
39
|
end
|
|
35
40
|
|
|
@@ -37,52 +42,58 @@ RSpec.describe ActiveJob::Retry do
|
|
|
37
42
|
let(:options) { {} }
|
|
38
43
|
|
|
39
44
|
specify do
|
|
40
|
-
expect {
|
|
45
|
+
expect { retry_instance }.
|
|
41
46
|
to raise_error(ActiveJob::Retry::InvalidConfigurationError)
|
|
42
47
|
end
|
|
43
48
|
end
|
|
44
49
|
end
|
|
45
50
|
|
|
46
51
|
describe '.exponential_retry' do
|
|
52
|
+
let(:strategy) { :exponential }
|
|
53
|
+
let(:options) { { limit: 10 } }
|
|
54
|
+
|
|
47
55
|
it 'sets an ExponentialBackoffStrategy' do
|
|
48
|
-
job.exponential_retry(limit: 10)
|
|
49
56
|
expect(job.backoff_strategy).to be_a(ActiveJob::Retry::ExponentialBackoffStrategy)
|
|
50
57
|
end
|
|
51
58
|
|
|
52
|
-
context 'invalid
|
|
59
|
+
context 'invalid limit' do
|
|
53
60
|
let(:options) { { limit: -2 } }
|
|
54
|
-
let(:options_with_delay) { { limit: 2, delay: 3 } }
|
|
55
61
|
|
|
56
62
|
specify do
|
|
57
|
-
expect {
|
|
63
|
+
expect { retry_instance }.
|
|
58
64
|
to raise_error(ActiveJob::Retry::InvalidConfigurationError)
|
|
59
65
|
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
context 'invalid option included' do
|
|
69
|
+
let(:options) { { limit: 2, delay: 3 } }
|
|
60
70
|
|
|
61
71
|
specify do
|
|
62
|
-
expect {
|
|
72
|
+
expect { retry_instance }.
|
|
63
73
|
to raise_error(ActiveJob::Retry::InvalidConfigurationError)
|
|
64
74
|
end
|
|
65
75
|
end
|
|
66
76
|
end
|
|
67
77
|
|
|
68
|
-
describe '
|
|
78
|
+
describe 'custom strategy' do
|
|
79
|
+
module CustomBackoffStrategy
|
|
80
|
+
def self.should_retry?(_attempt, _exception)
|
|
81
|
+
true
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.retry_delay(_attempt, _exception)
|
|
85
|
+
5
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
69
89
|
it 'rejects invalid backoff strategies' do
|
|
70
|
-
expect {
|
|
90
|
+
expect { described_class.new(strategy: Object.new) }.
|
|
71
91
|
to raise_error(ActiveJob::Retry::InvalidConfigurationError)
|
|
72
92
|
end
|
|
73
93
|
|
|
74
|
-
|
|
75
|
-
module CustomBackoffStrategy
|
|
76
|
-
def self.should_retry?(_attempt, _exception)
|
|
77
|
-
true
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def self.retry_delay(_attempt, _exception)
|
|
81
|
-
5
|
|
82
|
-
end
|
|
83
|
-
end
|
|
94
|
+
let(:strategy) { CustomBackoffStrategy }
|
|
84
95
|
|
|
85
|
-
|
|
96
|
+
it 'sets the backoff_strategy when it is valid' do
|
|
86
97
|
expect(job.backoff_strategy).to eq(CustomBackoffStrategy)
|
|
87
98
|
end
|
|
88
99
|
end
|
|
@@ -143,17 +154,16 @@ RSpec.describe ActiveJob::Retry do
|
|
|
143
154
|
end
|
|
144
155
|
|
|
145
156
|
describe '#rescue_with_handler' do
|
|
146
|
-
let(:
|
|
157
|
+
let(:mod) { described_class.new(strategy: :constant, limit: 100) }
|
|
147
158
|
let(:instance) { job.new }
|
|
148
|
-
before { job.retry_with(backoff_strategy) }
|
|
149
159
|
subject(:perform) { instance.perform_now }
|
|
150
160
|
|
|
151
161
|
context 'when the job should be retried' do
|
|
152
162
|
before do
|
|
153
|
-
expect(backoff_strategy).to receive(:should_retry?).
|
|
163
|
+
expect(job.backoff_strategy).to receive(:should_retry?).
|
|
154
164
|
with(1, instance_of(RuntimeError)).
|
|
155
165
|
and_return(true)
|
|
156
|
-
expect(backoff_strategy).to receive(:retry_delay).
|
|
166
|
+
expect(job.backoff_strategy).to receive(:retry_delay).
|
|
157
167
|
with(1, instance_of(RuntimeError)).
|
|
158
168
|
and_return(5)
|
|
159
169
|
end
|
|
@@ -179,7 +189,7 @@ RSpec.describe ActiveJob::Retry do
|
|
|
179
189
|
|
|
180
190
|
context 'when the job should not be retried' do
|
|
181
191
|
before do
|
|
182
|
-
expect(backoff_strategy).to receive(:should_retry?).
|
|
192
|
+
expect(job.backoff_strategy).to receive(:should_retry?).
|
|
183
193
|
with(1, instance_of(RuntimeError)).
|
|
184
194
|
and_return(false)
|
|
185
195
|
end
|
data/spec/spec_helper.rb
CHANGED
data/test/jobs/callback_job.rb
CHANGED
data/test/jobs/gid_job.rb
CHANGED
data/test/jobs/hello_job.rb
CHANGED
data/test/jobs/logging_job.rb
CHANGED
data/test/jobs/nested_job.rb
CHANGED
data/test/jobs/rescue_job.rb
CHANGED
|
@@ -12,10 +12,9 @@ CODE
|
|
|
12
12
|
|
|
13
13
|
file 'app/jobs/test_job.rb', <<-CODE
|
|
14
14
|
class TestJob < ActiveJob::Base
|
|
15
|
-
include ActiveJob::Retry
|
|
15
|
+
include ActiveJob::Retry.new(strategy: :constant, limit: 2, delay: 3)
|
|
16
16
|
|
|
17
17
|
queue_as :integration_tests
|
|
18
|
-
constant_retry limit: 2, delay: 3
|
|
19
18
|
|
|
20
19
|
rescue_from(RuntimeError) do |e|
|
|
21
20
|
if arguments[3]
|
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.
|
|
4
|
+
version: 0.6.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:
|
|
11
|
+
date: 2016-05-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activejob
|
|
@@ -151,7 +151,6 @@ files:
|
|
|
151
151
|
- test/adapters/sneakers.rb
|
|
152
152
|
- test/adapters/sucker_punch.rb
|
|
153
153
|
- test/cases/adapter_test.rb
|
|
154
|
-
- test/cases/argument_serialization_test.rb
|
|
155
154
|
- test/cases/callbacks_test.rb
|
|
156
155
|
- test/cases/job_serialization_test.rb
|
|
157
156
|
- test/cases/logging_test.rb
|
|
@@ -183,7 +182,7 @@ files:
|
|
|
183
182
|
- test/support/integration/test_case_helpers.rb
|
|
184
183
|
- test/support/job_buffer.rb
|
|
185
184
|
- test/support/que/inline.rb
|
|
186
|
-
homepage:
|
|
185
|
+
homepage: https://github.com/isaacseymour/activejob-retry
|
|
187
186
|
licenses:
|
|
188
187
|
- MIT
|
|
189
188
|
metadata: {}
|
|
@@ -203,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
203
202
|
version: '0'
|
|
204
203
|
requirements: []
|
|
205
204
|
rubyforge_project:
|
|
206
|
-
rubygems_version: 2.
|
|
205
|
+
rubygems_version: 2.5.1
|
|
207
206
|
signing_key:
|
|
208
207
|
specification_version: 4
|
|
209
208
|
summary: Automatic retry functionality for ActiveJob.
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
require 'helper'
|
|
2
|
-
require 'active_job/arguments'
|
|
3
|
-
require 'models/person'
|
|
4
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
|
5
|
-
|
|
6
|
-
class ArgumentSerializationTest < ActiveSupport::TestCase
|
|
7
|
-
setup do
|
|
8
|
-
@person = Person.find('5')
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
[ nil, 1, 1.0, 1_000_000_000_000_000_000_000,
|
|
12
|
-
'a', true, false,
|
|
13
|
-
[ 1, 'a' ],
|
|
14
|
-
{ 'a' => 1 }
|
|
15
|
-
].each do |arg|
|
|
16
|
-
test "serializes #{arg.class} verbatim" do
|
|
17
|
-
assert_arguments_unchanged arg
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
[ :a, Object.new, self, Person.find('5').to_gid ].each do |arg|
|
|
22
|
-
test "does not serialize #{arg.class}" do
|
|
23
|
-
assert_raises ActiveJob::SerializationError do
|
|
24
|
-
ActiveJob::Arguments.serialize [ arg ]
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
assert_raises ActiveJob::DeserializationError do
|
|
28
|
-
ActiveJob::Arguments.deserialize [ arg ]
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
test 'should convert records to Global IDs' do
|
|
34
|
-
assert_arguments_roundtrip [@person], ['_aj_globalid' => @person.to_gid.to_s]
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
test 'should dive deep into arrays and hashes' do
|
|
38
|
-
assert_arguments_roundtrip [3, [@person]], [3, ['_aj_globalid' => @person.to_gid.to_s]]
|
|
39
|
-
assert_arguments_roundtrip [{ 'a' => @person }], [{ 'a' => { '_aj_globalid' => @person.to_gid.to_s }}.with_indifferent_access]
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
test 'should stringify symbol hash keys' do
|
|
43
|
-
assert_equal [ 'a' => 1 ], ActiveJob::Arguments.serialize([ a: 1 ])
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
test 'should disallow non-string/symbol hash keys' do
|
|
47
|
-
assert_raises ActiveJob::SerializationError do
|
|
48
|
-
ActiveJob::Arguments.serialize [ { 1 => 2 } ]
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
assert_raises ActiveJob::SerializationError do
|
|
52
|
-
ActiveJob::Arguments.serialize [ { :a => [{ 2 => 3 }] } ]
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
assert_raises ActiveJob::SerializationError do
|
|
56
|
-
ActiveJob::Arguments.serialize [ '_aj_globalid' => 1 ]
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
assert_raises ActiveJob::SerializationError do
|
|
60
|
-
ActiveJob::Arguments.serialize [ :_aj_globalid => 1 ]
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
test 'should not allow non-primitive objects' do
|
|
65
|
-
assert_raises ActiveJob::SerializationError do
|
|
66
|
-
ActiveJob::Arguments.serialize [Object.new]
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
assert_raises ActiveJob::SerializationError do
|
|
70
|
-
ActiveJob::Arguments.serialize [1, [Object.new]]
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
private
|
|
75
|
-
def assert_arguments_unchanged(*args)
|
|
76
|
-
assert_arguments_roundtrip args, args
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def assert_arguments_roundtrip(args, expected_serialized_args)
|
|
80
|
-
serialized = ActiveJob::Arguments.serialize(args)
|
|
81
|
-
assert_equal expected_serialized_args, serialized
|
|
82
|
-
assert_equal args, ActiveJob::Arguments.deserialize(serialized)
|
|
83
|
-
end
|
|
84
|
-
end
|