sidekiq-robust-job 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +3 -0
- data/Gemfile.lock +2 -2
- data/README.md +27 -0
- data/lib/sidekiq/robust/job/version.rb +1 -1
- data/lib/sidekiq_robust_job/enqueue_conflict_resolution_strategy/drop_self.rb +0 -1
- data/lib/sidekiq_robust_job/repository.rb +5 -1
- data/lib/sidekiq_robust_job/sidekiq_job_manager.rb +17 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 29ab88d61f30457510da2f336be215a6604f2375583b16b7eaf608fe34cb37c5
|
4
|
+
data.tar.gz: c6a174c766334dee3ca28c9dc43b865f1d0f38b8bfce2021e2bcafeaab2b4724
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94388670e901388a0958d15715b4371235e6ef81e8dae86dd57f2340734fc911330c656bee9f39b11af897edcce0b6398e1214609fbb7f5de1a09fdcb5498b7d
|
7
|
+
data.tar.gz: 93ec3981822acf52de3b8191d88c9ef4fe904674412a43d498b4d1dd06ad395ef19321e303f72475685ce74696a8e6d18a691c67018e4b7a046163e70ba1bbd1
|
data/Changelog.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sidekiq-robust-job (0.
|
4
|
+
sidekiq-robust-job (0.2.0)
|
5
5
|
activesupport (>= 5)
|
6
6
|
sidekiq (>= 5)
|
7
7
|
sidekiq-cron (~> 1)
|
@@ -47,7 +47,7 @@ GEM
|
|
47
47
|
factory_bot_rails (6.1.0)
|
48
48
|
factory_bot (~> 6.1.0)
|
49
49
|
railties (>= 5.0.0)
|
50
|
-
fugit (1.4.
|
50
|
+
fugit (1.4.1)
|
51
51
|
et-orbi (~> 1.1, >= 1.1.8)
|
52
52
|
raabro (~> 1.4)
|
53
53
|
i18n (1.8.5)
|
data/README.md
CHANGED
@@ -57,6 +57,7 @@ class CreateSidekiqJobs < ActiveRecord::Migration[6.0]
|
|
57
57
|
t.datetime "execute_at"
|
58
58
|
t.string "sidekiq_jid"
|
59
59
|
|
60
|
+
t.index ["completed_at", "failed_at", "dropped_at"], name: "index_sidekiq_jobs_on_completed_at_and_failed_at_and_dropped_at"
|
60
61
|
t.index ["completed_at"], name: "index_sidekiq_jobs_on_completed_at", using: :brin
|
61
62
|
t.index ["created_at"], name: "index_sidekiq_jobs_on_created_at", using: :brin
|
62
63
|
t.index ["digest"], name: "index_sidekiq_jobs_on_digest"
|
@@ -144,6 +145,25 @@ Although keep in mind that using this feature comes with some performance penalt
|
|
144
145
|
|
145
146
|
If you have a lot of conflicts within a short period, consider using `perform_in` instead of `perform_async` and add some random number of seconds (ideally, below 1 minute) to make it easier to apply enqueue conflict resolution strategy.
|
146
147
|
|
148
|
+
If you enqueue a lot of the same jobs (same class, same arguments) in a short period of time and `drop_self` strategy, you should consider setting `persist_self_dropped_jobs` config option to false. By default, it's true which means that even the jobs that are dropped are persisted, which might be useful for some profiling or even figuring out in the first place that you have an issue like this. However, under such circumstances this is likely to result in heavier queries fetching a lot of rows from the database, causing a high database load.
|
149
|
+
|
150
|
+
Here is an example how to use it:
|
151
|
+
|
152
|
+
|
153
|
+
``` rb
|
154
|
+
class MyJob
|
155
|
+
include Sidekiq::Worker
|
156
|
+
include SidekiqRobustJob::SidekiqJobExtensions
|
157
|
+
|
158
|
+
sidekiq_options queue: "critical", enqueue_conflict_resolution_strategy: "drop_self",
|
159
|
+
persist_self_dropped_jobs: false
|
160
|
+
|
161
|
+
def call(user_id)
|
162
|
+
User.find(user_id).do_something
|
163
|
+
end
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
147
167
|
#### Execution Uniqueness (Mutex)
|
148
168
|
|
149
169
|
This feature is about handling a "conflict" (determined by a digest generated based on the job class and its arguments) when there is already the "same job" getting executed (i.e. same job class and arguments) at the same time.
|
@@ -269,12 +289,19 @@ expect {
|
|
269
289
|
}.to enqueue_sidekiq_robust_job(MyJob).with(user.id).at(5.seconds.from_now)
|
270
290
|
```
|
271
291
|
|
292
|
+
|
293
|
+
There is also a negated matcher: `not_enqueue_sidekiq_robust_job`.
|
294
|
+
|
272
295
|
### How to migrate already enqueued jobs when introducing the gem?
|
273
296
|
|
274
297
|
This might be a bit tricky. You might consider using new job classes temporarily so that the already existing jobs are performed and the new ones are getting enqueued and then use again the original class with `SidekiqRobustJob::SidekiqJobExtensions` included and `call` method defined.
|
275
298
|
|
276
299
|
You can also stop workers, iterate over all existing jobs, re-schedule them (after including the module) and delete them - it's safe because the actual job will still be there, but it will be enqueued this time with job's ID and `call` method will be used. And you need to delete the original ones as they might have either a different `perform` method signature, or when having the same one, the argument will have a different meaning that job's ID, which can cause an unexpected behavior. This might require a downtime if you are not able to distinguish just based on the arguments of the job between the previous way of executing jobs and the new one. If you are able to, the downtime might not be required, but a lot of jobs can fail due to `perform` method's signature change. However, you can also re-enqueue these jobs and delete them from `RetrySet`.
|
277
300
|
|
301
|
+
### Maintenance
|
302
|
+
|
303
|
+
It is recommended to periodically remove old jobs for the maximum performance. [Tartarus](https://github.com/BookingSync/tartarus-rb) is a recommended approach for that.
|
304
|
+
|
278
305
|
## Development
|
279
306
|
|
280
307
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -17,13 +17,17 @@ class SidekiqRobustJob
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def save(record)
|
20
|
-
record.save!
|
20
|
+
record.save! if record.changed?
|
21
21
|
end
|
22
22
|
|
23
23
|
def create(attributes)
|
24
24
|
jobs_database.create!(attributes)
|
25
25
|
end
|
26
26
|
|
27
|
+
def build(attributes)
|
28
|
+
jobs_database.new(attributes)
|
29
|
+
end
|
30
|
+
|
27
31
|
def missed_jobs(missed_job_policy:)
|
28
32
|
jobs_database
|
29
33
|
.where(completed_at: nil, dropped_at: nil, failed_at: nil)
|
@@ -53,7 +53,7 @@ class SidekiqRobustJob
|
|
53
53
|
private
|
54
54
|
|
55
55
|
def create_job(job_class, *arguments)
|
56
|
-
jobs_repository.
|
56
|
+
jobs_repository.build(
|
57
57
|
job_class: job_class,
|
58
58
|
arguments: Array.wrap(arguments),
|
59
59
|
enqueued_at: clock.now,
|
@@ -64,9 +64,10 @@ class SidekiqRobustJob
|
|
64
64
|
enqueue_conflict_resolution_strategy: job_class.get_sidekiq_options.fetch("enqueue_conflict_resolution_strategy",
|
65
65
|
SidekiqRobustJob::EnqueueConflictResolutionStrategy.do_nothing)
|
66
66
|
).tap do |job|
|
67
|
+
jobs_repository.save(job) if persist_job_immediately?(job_class)
|
67
68
|
jobs_repository.transaction do
|
68
69
|
resolve_potential_conflict_for_enqueueing(job)
|
69
|
-
jobs_repository.save(job)
|
70
|
+
jobs_repository.save(job) if persist_after_resolving_conflict_for_enqueueing(job, job_class)
|
70
71
|
end
|
71
72
|
end
|
72
73
|
end
|
@@ -76,5 +77,19 @@ class SidekiqRobustJob
|
|
76
77
|
.resolve(job.enqueue_conflict_resolution_strategy)
|
77
78
|
.execute(job)
|
78
79
|
end
|
80
|
+
|
81
|
+
def persist_job_immediately?(job_class)
|
82
|
+
persist_self_dropped_jobs?(job_class)
|
83
|
+
end
|
84
|
+
|
85
|
+
def persist_after_resolving_conflict_for_enqueueing(job, job_class)
|
86
|
+
return true if persist_self_dropped_jobs?(job_class)
|
87
|
+
|
88
|
+
!job.dropped?
|
89
|
+
end
|
90
|
+
|
91
|
+
def persist_self_dropped_jobs?(job_class)
|
92
|
+
job_class.get_sidekiq_options.fetch("persist_self_dropped_jobs", true)
|
93
|
+
end
|
79
94
|
end
|
80
95
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-robust-job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karol Galanciak
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sidekiq
|