acidic_job 1.0.0.pre10 → 1.0.0.pre11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +42 -0
- data/lib/acidic_job/extensions/action_mailer.rb +3 -5
- data/lib/acidic_job/extensions/active_job.rb +2 -4
- data/lib/acidic_job/extensions/noticed.rb +5 -7
- data/lib/acidic_job/extensions/sidekiq.rb +2 -4
- data/lib/acidic_job/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 53b5f12879bffb6a461e3574b96f8a41464ec83ce0a21eaa8e244261ce53a9be
|
4
|
+
data.tar.gz: 7b90c9864347564706466e62c61f08eb377d8e3a33475ad40ba559de59e7b70e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08b4a0bdd41ac80f8ac879003f455f577f93fc431acdb780dfd3e54260b07a61bf0557c3e7d99192e1ad809134b709211fd2c5efe581b797563187dcfbb34467'
|
7
|
+
data.tar.gz: 66e8b3bfe0226c3e1f5168d45431a01a36ee3dfb796c855c49fc009296cb223d33922bc2db5febbe6d6453b4a01c46661b805aa1e2c80a4e37f3dce183b5e748
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -64,6 +64,7 @@ It provides a suite of functionality that empowers you to create complex, robust
|
|
64
64
|
* Transactional Steps — break your job into a series of steps, each of which will be run within an acidic database transaction, allowing retries to jump back to the last "recovery point".
|
65
65
|
* Persisted Attributes — when retrying jobs at later steps, we need to ensure that data created in previous steps is still available to later steps on retry.
|
66
66
|
* Transactionally Staged Jobs — enqueue additional jobs within the acidic transaction safely
|
67
|
+
* Custom Idempotency Keys — use something other than the job ID for the idempotency key of the job run
|
67
68
|
* Sidekiq Callbacks — bring ActiveJob-like callbacks into your pure Sidekiq Workers
|
68
69
|
* Sidekiq Batches — leverage the power of Sidekiq Pro's `batch` functionality without the hassle
|
69
70
|
|
@@ -163,6 +164,47 @@ class RideCreateJob < ActiveJob::Base
|
|
163
164
|
end
|
164
165
|
```
|
165
166
|
|
167
|
+
### Custom Idempotency Keys
|
168
|
+
|
169
|
+
By default, `AcidicJob` uses the job identifier provided by the queueing system (ActiveJob or Sidekiq) as the idempotency key for the job run. The idempotency key is what is used to guarantee that no two runs of the same job occur. However, sometimes we need particular jobs to be idempotent based on some other criteria. In these cases, `AcidicJob` provides a collection of tools to allow you to ensure the idempotency of your jobs.
|
170
|
+
|
171
|
+
Firstly, you can configure your job class to explicitly use either the job identifier or the job arguments as the foundation for the idempotency key. A job class that calls the `acidic_by_job_id` class method (which is the default behavior) will simply make the job run's idempotency key the job's identifier:
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
class ExampleJob < ActiveJob::Base
|
175
|
+
include AcidicJob
|
176
|
+
acidic_by_job_id
|
177
|
+
|
178
|
+
def perform
|
179
|
+
end
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
183
|
+
Conversely, a job class can use the `acidic_by_job_args` method to configure that job class to use the arguments passed to the job as the foundation for the job run's idempotency key:
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
class ExampleJob < ActiveJob::Base
|
187
|
+
include AcidicJob
|
188
|
+
acidic_by_job_args
|
189
|
+
|
190
|
+
def perform(arg_1, arg_2)
|
191
|
+
# the idempotency key will be based on whatever the values of `arg_1` and `arg_2` are
|
192
|
+
end
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
196
|
+
These options cover the two common situations, but sometimes our systems need finer-grained control. For example, our job might take some record as the job argument, but we need to use a combination of the record identifier and record status as the foundation for the idempotency key. In these cases we can't configure the idempotency key logic at the class level, so instead we can provide the logic when enqueuing the job itself.
|
197
|
+
|
198
|
+
When you call any `deliver_acidicly` or `perform_acidicly` method you can pass an optional `unique_by` argument which will be used to generate the idempotency key:
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
ExampleJob.perform_acidicly(unique_by: { id: record.id, status: record.status })
|
202
|
+
UserMailer.with(user, record).deliver_acidicly(unique_by: [user.id, record.id, record.status])
|
203
|
+
```
|
204
|
+
|
205
|
+
As you see, the value to the `unique_by` option can be a Hash or an Array or even a simple scalar value.
|
206
|
+
|
207
|
+
|
166
208
|
### Sidekiq Callbacks
|
167
209
|
|
168
210
|
In order to ensure that `AcidicJob::Staged` records are only destroyed once the related job has been successfully performed, whether it is an ActiveJob or a Sidekiq Worker, `acidic_job` also extends Sidekiq to support the [ActiveJob callback interface](https://edgeguides.rubyonrails.org/active_job_basics.html#callbacks).
|
@@ -7,17 +7,15 @@ module AcidicJob
|
|
7
7
|
module ActionMailer
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
|
-
def deliver_acidicly(_options = {},
|
10
|
+
def deliver_acidicly(_options = {}, unique_by: nil)
|
11
11
|
job_class = ::ActionMailer::MailDeliveryJob
|
12
12
|
|
13
13
|
job_args = [@mailer_class.name, @action.to_s, "deliver_now", @params, *@args]
|
14
14
|
# for Sidekiq, this depends on the Sidekiq::Serialization extension
|
15
15
|
serialized_job = job_class.new(job_args).serialize
|
16
16
|
acidic_identifier = job_class.respond_to?(:acidic_identifier) ? job_class.acidic_identifier : :job_id
|
17
|
-
# use either [1] provided
|
18
|
-
key = if
|
19
|
-
idempotency_key
|
20
|
-
elsif unique_by
|
17
|
+
# use either [1] provided uniqueness constraint or [2] computed key
|
18
|
+
key = if unique_by
|
21
19
|
IdempotencyKey.generate(unique_by: unique_by, job_class: job_class.name)
|
22
20
|
else
|
23
21
|
IdempotencyKey.new(acidic_identifier).value_for(serialized_job)
|
@@ -24,10 +24,8 @@ module AcidicJob
|
|
24
24
|
raise UnsupportedExtension unless defined?(::ActiveJob) && self < ::ActiveJob::Base
|
25
25
|
|
26
26
|
serialized_job = serialize_with_arguments(*args, **kwargs)
|
27
|
-
# use either [1] provided
|
28
|
-
key = if kwargs.key?(:
|
29
|
-
kwargs[:idempotency_key] || kwargs["idempotency_key"]
|
30
|
-
elsif kwargs.key?(:unique_by) || kwargs.key?("unique_by")
|
27
|
+
# use either [1] provided uniqueness constraint or [2] computed key
|
28
|
+
key = if kwargs.key?(:unique_by) || kwargs.key?("unique_by")
|
31
29
|
unique_by = [kwargs[:unique_by], kwargs["unique_by"]].compact.first
|
32
30
|
IdempotencyKey.generate(unique_by: unique_by, job_class: name)
|
33
31
|
else
|
@@ -6,12 +6,12 @@ module AcidicJob
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
class_methods do
|
9
|
-
def deliver_acidicly(recipients,
|
10
|
-
new.deliver_acidicly(recipients,
|
9
|
+
def deliver_acidicly(recipients, unique_by: nil)
|
10
|
+
new.deliver_acidicly(recipients, unique_by: unique_by)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def deliver_acidicly(recipients,
|
14
|
+
def deliver_acidicly(recipients, unique_by: nil)
|
15
15
|
# THIS IS A HACK THAT COPIES AND PASTES KEY PARTS OF THE `Noticed::Base` CODE
|
16
16
|
# IN ORDER TO ALLOW US TO TRANSACTIONALLY DELIVER NOTIFICATIONS
|
17
17
|
# THIS IS THUS LIABLE TO BREAK WHENEVER THAT GEM IS UPDATED
|
@@ -37,10 +37,8 @@ module AcidicJob
|
|
37
37
|
}
|
38
38
|
serialized_job = job_class.send(:job_or_instantiate, args).serialize
|
39
39
|
acidic_identifier = job_class.respond_to?(:acidic_identifier) ? job_class.acidic_identifier : :job_id
|
40
|
-
# use either [1] provided
|
41
|
-
key = if
|
42
|
-
idempotency_key
|
43
|
-
elsif unique_by
|
40
|
+
# use either [1] provided uniqueness constraint or [2] computed key
|
41
|
+
key = if unique_by
|
44
42
|
IdempotencyKey.generate(unique_by: unique_by, job_class: job_class.name)
|
45
43
|
else
|
46
44
|
IdempotencyKey.new(acidic_identifier).value_for(serialized_job)
|
@@ -58,10 +58,8 @@ module AcidicJob
|
|
58
58
|
class_methods do
|
59
59
|
def perform_acidicly(*args, **kwargs)
|
60
60
|
serialized_job = serialize_with_arguments(*args, **kwargs)
|
61
|
-
# use either [1] provided
|
62
|
-
key = if kwargs.key?(:
|
63
|
-
kwargs[:idempotency_key] || kwargs["idempotency_key"]
|
64
|
-
elsif kwargs.key?(:unique_by) || kwargs.key?("unique_by")
|
61
|
+
# use either [1] provided uniqueness constraint or [2] computed key
|
62
|
+
key = if kwargs.key?(:unique_by) || kwargs.key?("unique_by")
|
65
63
|
unique_by = [kwargs[:unique_by], kwargs["unique_by"]].compact.first
|
66
64
|
IdempotencyKey.generate(unique_by: unique_by, job_class: name)
|
67
65
|
else
|
data/lib/acidic_job/version.rb
CHANGED