inst-jobs 3.0.8 → 3.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/db/migrate/20220328152900_add_failed_jobs_indicies.rb +12 -0
- data/lib/delayed/backend/active_record.rb +19 -4
- data/lib/delayed/periodic.rb +1 -1
- data/lib/delayed/settings.rb +1 -1
- data/lib/delayed/version.rb +1 -1
- data/lib/delayed/worker/health_check.rb +1 -1
- data/spec/active_record_job_spec.rb +22 -13
- data/spec/delayed/work_queue/in_process_spec.rb +1 -1
- data/spec/delayed/work_queue/parent_process/server_spec.rb +1 -1
- data/spec/delayed/worker_spec.rb +1 -1
- data/spec/shared/delayed_batch.rb +3 -3
- data/spec/shared/delayed_method.rb +1 -1
- data/spec/shared/shared_backend.rb +33 -33
- data/spec/shared/worker.rb +3 -3
- data/spec/spec_helper.rb +4 -2
- metadata +8 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee779fa187d057bce265940ca1c9c2944bdf096ab198060e0819ff40dd02358b
|
4
|
+
data.tar.gz: bc930f9dc0ca659df54388753dc9aa26402c866023b7f275155897ccca35ebf4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd24bd19e153cb7f48b33911e38fbd9657de396baad1c32286d5a4acb899d23f9d97c627914c095647006129f5c0ebc008e7e07b311f3d33b89819e400cce756
|
7
|
+
data.tar.gz: 005e7e0a637b1e5a3fcae2b7e22edfb2af604da2328e273f512b4747dacb4d723afc06bd4846246c3fc541f72ca7068123c98bf26b52e2964f7eaa45dba6b609
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddFailedJobsIndicies < ActiveRecord::Migration[5.2]
|
4
|
+
disable_ddl_transaction!
|
5
|
+
|
6
|
+
def change
|
7
|
+
add_index :failed_jobs, :failed_at, algorithm: :concurrently
|
8
|
+
add_index :failed_jobs, :strand, where: "strand IS NOT NULL", algorithm: :concurrently
|
9
|
+
add_index :failed_jobs, :singleton, where: "singleton IS NOT NULL", algorithm: :concurrently
|
10
|
+
add_index :failed_jobs, :tag, algorithm: :concurrently
|
11
|
+
end
|
12
|
+
end
|
@@ -62,11 +62,21 @@ module Delayed
|
|
62
62
|
_write_attribute(column, current_time) unless attribute_present?(column)
|
63
63
|
end
|
64
64
|
|
65
|
-
attribute_names =
|
65
|
+
attribute_names = if Rails.version < "7.0"
|
66
|
+
attribute_names_for_partial_writes
|
67
|
+
else
|
68
|
+
attribute_names_for_partial_inserts
|
69
|
+
end
|
66
70
|
attribute_names = attributes_for_create(attribute_names)
|
67
71
|
values = attributes_with_values(attribute_names)
|
68
72
|
|
69
|
-
im =
|
73
|
+
im = if Rails.version < "7.0"
|
74
|
+
self.class.arel_table.compile_insert(self.class.send(:_substitute_values, values))
|
75
|
+
else
|
76
|
+
im = Arel::InsertManager.new(self.class.arel_table)
|
77
|
+
im.insert(values.transform_keys { |name| self.class.arel_table[name] })
|
78
|
+
im
|
79
|
+
end
|
70
80
|
|
71
81
|
lock_and_insert = values["strand"] && instance_of?(Job)
|
72
82
|
# can't use prepared statements if we're combining multiple statemenets
|
@@ -101,7 +111,8 @@ module Delayed
|
|
101
111
|
# but we don't need to lock when inserting into Delayed::Failed
|
102
112
|
if values["strand"] && instance_of?(Job)
|
103
113
|
fn_name = connection.quote_table_name("half_md5_as_bigint")
|
104
|
-
|
114
|
+
quoted_strand = connection.quote(Rails.version < "7.0" ? values["strand"] : values["strand"].value)
|
115
|
+
sql = "SELECT pg_advisory_xact_lock(#{fn_name}(#{quoted_strand})); #{sql}"
|
105
116
|
end
|
106
117
|
result = connection.execute(sql, "#{self.class} Create")
|
107
118
|
self.id = result.values.first&.first
|
@@ -471,7 +482,7 @@ module Delayed
|
|
471
482
|
transaction do
|
472
483
|
# for db performance reasons, we only need one process doing this at a time
|
473
484
|
# so if we can't get an advisory lock, just abort. we'll try again soon
|
474
|
-
|
485
|
+
next unless attempt_advisory_lock(prefetch_jobs_lock_name)
|
475
486
|
|
476
487
|
horizon = db_time_now - (Settings.parent_process[:prefetched_jobs_timeout] * 4)
|
477
488
|
where("locked_by LIKE 'prefetch:%' AND locked_at<?", horizon).update_all(locked_at: nil, locked_by: nil)
|
@@ -568,6 +579,10 @@ module Delayed
|
|
568
579
|
class Failed < Job
|
569
580
|
include Delayed::Backend::Base
|
570
581
|
self.table_name = :failed_jobs
|
582
|
+
|
583
|
+
def self.cleanup_old_jobs(before_date, batch_size: 10_000)
|
584
|
+
where("failed_at < ?", before_date).in_batches(of: batch_size).delete_all
|
585
|
+
end
|
571
586
|
end
|
572
587
|
end
|
573
588
|
end
|
data/lib/delayed/periodic.rb
CHANGED
@@ -36,7 +36,7 @@ module Delayed
|
|
36
36
|
Delayed::Job.transaction do
|
37
37
|
# for db performance reasons, we only need one process doing this at a time
|
38
38
|
# so if we can't get an advisory lock, just abort. we'll try again soon
|
39
|
-
|
39
|
+
next unless Delayed::Job.attempt_advisory_lock("Delayed::Periodic#audit_queue")
|
40
40
|
|
41
41
|
perform_audit!
|
42
42
|
end
|
data/lib/delayed/settings.rb
CHANGED
@@ -135,7 +135,7 @@ module Delayed
|
|
135
135
|
self.num_strands = ->(_strand_name) {}
|
136
136
|
self.default_job_options = -> { {} }
|
137
137
|
self.job_detailed_log_format = lambda { |job|
|
138
|
-
job.to_json(include_root: false, only: %w[tag strand priority attempts created_at max_attempts source])
|
138
|
+
job.to_json(include_root: false, only: %w[tag strand singleton priority attempts created_at max_attempts source])
|
139
139
|
}
|
140
140
|
|
141
141
|
# Send workers KILL after QUIT if they haven't exited within the
|
data/lib/delayed/version.rb
CHANGED
@@ -34,7 +34,7 @@ module Delayed
|
|
34
34
|
# no other worker is trying to do this right now (and if we abandon the
|
35
35
|
# operation, the transaction will end, releasing the advisory lock).
|
36
36
|
result = Delayed::Job.attempt_advisory_lock("Delayed::Worker::HealthCheck#reschedule_abandoned_jobs")
|
37
|
-
|
37
|
+
next unless result
|
38
38
|
|
39
39
|
horizon = 5.minutes.ago
|
40
40
|
|
@@ -28,13 +28,13 @@ describe "Delayed::Backed::ActiveRecord::Job" do
|
|
28
28
|
|
29
29
|
it "does not allow a second worker to get exclusive access if already successfully processed by worker1" do
|
30
30
|
@job.destroy
|
31
|
-
expect(@job_copy_for_worker2.send(:lock_exclusively!, "worker2")).to
|
31
|
+
expect(@job_copy_for_worker2.send(:lock_exclusively!, "worker2")).to be(false)
|
32
32
|
end
|
33
33
|
|
34
34
|
it "doesn't allow a second worker to get exclusive access if failed to be " \
|
35
35
|
"processed by worker1 and run_at time is now in future (due to backing off behaviour)" do
|
36
36
|
@job.update(attempts: 1, run_at: 1.day.from_now)
|
37
|
-
expect(@job_copy_for_worker2.send(:lock_exclusively!, "worker2")).to
|
37
|
+
expect(@job_copy_for_worker2.send(:lock_exclusively!, "worker2")).to be(false)
|
38
38
|
end
|
39
39
|
|
40
40
|
it "selects the next job at random if enabled" do
|
@@ -55,13 +55,13 @@ describe "Delayed::Backed::ActiveRecord::Job" do
|
|
55
55
|
|
56
56
|
it "unlocks a successfully locked job and persist the job's unlocked state" do
|
57
57
|
job = Delayed::Job.create payload_object: SimpleJob.new
|
58
|
-
expect(job.send(:lock_exclusively!, "worker1")).to
|
58
|
+
expect(job.send(:lock_exclusively!, "worker1")).to be(true)
|
59
59
|
job.reload
|
60
60
|
job.unlock
|
61
61
|
job.save!
|
62
62
|
job.reload
|
63
|
-
expect(job.locked_by).to
|
64
|
-
expect(job.locked_at).to
|
63
|
+
expect(job.locked_by).to be_nil
|
64
|
+
expect(job.locked_at).to be_nil
|
65
65
|
end
|
66
66
|
|
67
67
|
describe "bulk_update failed jobs" do
|
@@ -85,7 +85,7 @@ describe "Delayed::Backed::ActiveRecord::Job" do
|
|
85
85
|
before do
|
86
86
|
2.times do
|
87
87
|
j = Delayed::Job.create(payload_object: SimpleJob.new)
|
88
|
-
expect(j.send(:lock_exclusively!, "worker1")).to
|
88
|
+
expect(j.send(:lock_exclusively!, "worker1")).to be(true)
|
89
89
|
j.fail!
|
90
90
|
end
|
91
91
|
end
|
@@ -100,6 +100,15 @@ describe "Delayed::Backed::ActiveRecord::Job" do
|
|
100
100
|
failed_count = Delayed::Job::Failed.count
|
101
101
|
expect(Delayed::Job.bulk_update("destroy", flavor: "failed", query: @query)).to eq(failed_count)
|
102
102
|
end
|
103
|
+
|
104
|
+
it "deletes all failed jobs before a given date" do
|
105
|
+
Delayed::Job::Failed.first.update!(failed_at: 3.hours.ago)
|
106
|
+
Delayed::Job::Failed.last.update!(failed_at: 1.hour.ago)
|
107
|
+
|
108
|
+
expect(Delayed::Job::Failed.count).to eq 2
|
109
|
+
Delayed::Job::Failed.cleanup_old_jobs(2.hours.ago)
|
110
|
+
expect(Delayed::Job::Failed.count).to eq 1
|
111
|
+
end
|
103
112
|
end
|
104
113
|
end
|
105
114
|
|
@@ -170,13 +179,13 @@ describe "Delayed::Backed::ActiveRecord::Job" do
|
|
170
179
|
it "sets one job as next_in_strand at a time with max_concurrent of 1" do
|
171
180
|
job1 = Delayed::Job.enqueue(SimpleJob.new, n_strand: ["njobs"])
|
172
181
|
job1.reload
|
173
|
-
expect(job1.next_in_strand).to
|
182
|
+
expect(job1.next_in_strand).to be(true)
|
174
183
|
job2 = Delayed::Job.enqueue(SimpleJob.new, n_strand: ["njobs"])
|
175
184
|
job2.reload
|
176
|
-
expect(job2.next_in_strand).to
|
185
|
+
expect(job2.next_in_strand).to be(false)
|
177
186
|
run_job(job1)
|
178
187
|
job2.reload
|
179
|
-
expect(job2.next_in_strand).to
|
188
|
+
expect(job2.next_in_strand).to be(true)
|
180
189
|
end
|
181
190
|
|
182
191
|
it "sets multiple jobs as next_in_strand at a time based on max_concurrent" do
|
@@ -187,16 +196,16 @@ describe "Delayed::Backed::ActiveRecord::Job" do
|
|
187
196
|
}) do
|
188
197
|
job1 = Delayed::Job.enqueue(SimpleJob.new, n_strand: ["njobs"])
|
189
198
|
job1.reload
|
190
|
-
expect(job1.next_in_strand).to
|
199
|
+
expect(job1.next_in_strand).to be(true)
|
191
200
|
job2 = Delayed::Job.enqueue(SimpleJob.new, n_strand: ["njobs"])
|
192
201
|
job2.reload
|
193
|
-
expect(job2.next_in_strand).to
|
202
|
+
expect(job2.next_in_strand).to be(true)
|
194
203
|
job3 = Delayed::Job.enqueue(SimpleJob.new, n_strand: ["njobs"])
|
195
204
|
job3.reload
|
196
|
-
expect(job3.next_in_strand).to
|
205
|
+
expect(job3.next_in_strand).to be(false)
|
197
206
|
run_job(job1)
|
198
207
|
job3.reload
|
199
|
-
expect(job3.next_in_strand).to
|
208
|
+
expect(job3.next_in_strand).to be(true)
|
200
209
|
end
|
201
210
|
end
|
202
211
|
end
|
@@ -255,7 +255,7 @@ RSpec.describe Delayed::WorkQueue::ParentProcess::Server do
|
|
255
255
|
subject.run_once
|
256
256
|
|
257
257
|
expect(Marshal.load(client)).to eq(job)
|
258
|
-
expect(called).to
|
258
|
+
expect(called).to be(true)
|
259
259
|
end
|
260
260
|
|
261
261
|
it "deletes the correct worker when transferring jobs" do
|
data/spec/delayed/worker_spec.rb
CHANGED
@@ -81,7 +81,7 @@ describe Delayed::Worker do
|
|
81
81
|
short_log_format = subject.log_job(job, :short)
|
82
82
|
expect(short_log_format).to eq("RSpec::Mocks::Double")
|
83
83
|
long_format = subject.log_job(job, :long)
|
84
|
-
expect(long_format).to eq("RSpec::Mocks::Double {\"priority\":25,\"attempts\":0,\"created_at\":null,\"tag\":\"RSpec::Mocks::Double#perform\",\"max_attempts\":null,\"strand\":\"test_jobs\",\"source\":null}") # rubocop:disable Layout/LineLength
|
84
|
+
expect(long_format).to eq("RSpec::Mocks::Double {\"priority\":25,\"attempts\":0,\"created_at\":null,\"tag\":\"RSpec::Mocks::Double#perform\",\"max_attempts\":null,\"strand\":\"test_jobs\",\"source\":null,\"singleton\":null}") # rubocop:disable Layout/LineLength
|
85
85
|
end
|
86
86
|
|
87
87
|
it "logging format can be changed with settings" do
|
@@ -13,10 +13,10 @@ shared_examples_for "Delayed::Batch" do
|
|
13
13
|
batch_jobs = Delayed::Job.find_available(5)
|
14
14
|
regular_jobs = Delayed::Job.list_jobs(:future, 5)
|
15
15
|
expect(regular_jobs.size).to eq(1)
|
16
|
-
expect(regular_jobs.first.batch?).to
|
16
|
+
expect(regular_jobs.first.batch?).to be(false)
|
17
17
|
expect(batch_jobs.size).to eq(1)
|
18
18
|
batch_job = batch_jobs.first
|
19
|
-
expect(batch_job.batch?).to
|
19
|
+
expect(batch_job.batch?).to be(true)
|
20
20
|
expect(batch_job.payload_object.mode).to eq(:serial)
|
21
21
|
expect(batch_job.payload_object.jobs.map do |j|
|
22
22
|
[j.payload_object.object, j.payload_object.method, j.payload_object.args]
|
@@ -50,7 +50,7 @@ shared_examples_for "Delayed::Batch" do
|
|
50
50
|
expect(Delayed::Job.jobs_count(:current)).to eq(1)
|
51
51
|
|
52
52
|
batch_job = Delayed::Job.find_available(1).first
|
53
|
-
expect(batch_job.batch?).to
|
53
|
+
expect(batch_job.batch?).to be(true)
|
54
54
|
jobs = batch_job.payload_object.jobs
|
55
55
|
expect(jobs.size).to eq(2)
|
56
56
|
expect(jobs[0]).to be_new_record
|
@@ -140,7 +140,7 @@ shared_examples_for "random ruby objects" do
|
|
140
140
|
obj.test_method(7, synchronous: true)
|
141
141
|
expect(obj.ran).to eq([7])
|
142
142
|
obj.ran = nil
|
143
|
-
expect(obj.ran).to
|
143
|
+
expect(obj.ran).to be_nil
|
144
144
|
obj.test_method(8, 9, synchronous: true)
|
145
145
|
expect(obj.ran).to eq([8, 9])
|
146
146
|
end
|
@@ -233,7 +233,7 @@ shared_examples_for "a backend" do
|
|
233
233
|
describe "#transfer_lock" do
|
234
234
|
it "works" do
|
235
235
|
job = create_job(locked_by: "worker", locked_at: Delayed::Job.db_time_now)
|
236
|
-
expect(job.transfer_lock!(from: "worker", to: "worker2")).to
|
236
|
+
expect(job.transfer_lock!(from: "worker", to: "worker2")).to be true
|
237
237
|
expect(Delayed::Job.find(job.id).locked_by).to eq "worker2"
|
238
238
|
end
|
239
239
|
end
|
@@ -243,13 +243,13 @@ shared_examples_for "a backend" do
|
|
243
243
|
job1 = create_job(strand: "myjobs")
|
244
244
|
job2 = create_job(strand: "myjobs")
|
245
245
|
expect(Delayed::Job.get_and_lock_next_available("w1")).to eq(job1)
|
246
|
-
expect(Delayed::Job.get_and_lock_next_available("w2")).to
|
246
|
+
expect(Delayed::Job.get_and_lock_next_available("w2")).to be_nil
|
247
247
|
job1.destroy
|
248
248
|
# update time since the failed lock pushed it forward
|
249
249
|
job2.run_at = 1.minute.ago
|
250
250
|
job2.save!
|
251
251
|
expect(Delayed::Job.get_and_lock_next_available("w3")).to eq(job2)
|
252
|
-
expect(Delayed::Job.get_and_lock_next_available("w4")).to
|
252
|
+
expect(Delayed::Job.get_and_lock_next_available("w4")).to be_nil
|
253
253
|
end
|
254
254
|
|
255
255
|
it "fails to lock if an earlier job gets locked" do
|
@@ -301,7 +301,7 @@ shared_examples_for "a backend" do
|
|
301
301
|
locked = [Delayed::Job.get_and_lock_next_available("w1"),
|
302
302
|
Delayed::Job.get_and_lock_next_available("w2")]
|
303
303
|
expect(jobs).to eq locked
|
304
|
-
expect(Delayed::Job.get_and_lock_next_available("w3")).to
|
304
|
+
expect(Delayed::Job.get_and_lock_next_available("w3")).to be_nil
|
305
305
|
end
|
306
306
|
|
307
307
|
it "does not interfere with jobs in other strands" do
|
@@ -309,7 +309,7 @@ shared_examples_for "a backend" do
|
|
309
309
|
locked = [Delayed::Job.get_and_lock_next_available("w1"),
|
310
310
|
Delayed::Job.get_and_lock_next_available("w2")]
|
311
311
|
expect(jobs).to eq locked
|
312
|
-
expect(Delayed::Job.get_and_lock_next_available("w3")).to
|
312
|
+
expect(Delayed::Job.get_and_lock_next_available("w3")).to be_nil
|
313
313
|
end
|
314
314
|
|
315
315
|
it "does not find next jobs when given no priority" do
|
@@ -317,7 +317,7 @@ shared_examples_for "a backend" do
|
|
317
317
|
first = Delayed::Job.get_and_lock_next_available("w1", Delayed::Settings.queue, nil, nil)
|
318
318
|
second = Delayed::Job.get_and_lock_next_available("w2", Delayed::Settings.queue, nil, nil)
|
319
319
|
expect(first).to eq jobs.first
|
320
|
-
expect(second).to
|
320
|
+
expect(second).to be_nil
|
321
321
|
end
|
322
322
|
|
323
323
|
it "complains if you pass more than one strand-based option" do
|
@@ -389,7 +389,7 @@ shared_examples_for "a backend" do
|
|
389
389
|
expect(job1.reload.handler).to include("ErrorJob")
|
390
390
|
end
|
391
391
|
|
392
|
-
context "next_in_strand management - deadlocks and race conditions", non_transactional: true do
|
392
|
+
context "next_in_strand management - deadlocks and race conditions", non_transactional: true, slow: true do
|
393
393
|
# The following unit tests are fairly slow and non-deterministic. It may be
|
394
394
|
# easier to make them fail quicker and more consistently by adding a random
|
395
395
|
# sleep into the appropriate trigger(s).
|
@@ -538,11 +538,11 @@ shared_examples_for "a backend" do
|
|
538
538
|
Delayed::Job.get_and_lock_next_available("w1")
|
539
539
|
@job2 = create_job(singleton: "myjobs")
|
540
540
|
|
541
|
-
expect(@job1.reload.next_in_strand).to
|
542
|
-
expect(@job2.reload.next_in_strand).to
|
541
|
+
expect(@job1.reload.next_in_strand).to be true
|
542
|
+
expect(@job2.reload.next_in_strand).to be false
|
543
543
|
|
544
544
|
@job1.destroy
|
545
|
-
expect(@job2.reload.next_in_strand).to
|
545
|
+
expect(@job2.reload.next_in_strand).to be true
|
546
546
|
end
|
547
547
|
|
548
548
|
it "handles transitions correctly when going from not stranded to stranded" do
|
@@ -552,13 +552,13 @@ shared_examples_for "a backend" do
|
|
552
552
|
Delayed::Job.get_and_lock_next_available("w1")
|
553
553
|
@job3 = create_job(singleton: "myjobs", strand: "myjobs2")
|
554
554
|
|
555
|
-
expect(@job1.reload.next_in_strand).to
|
556
|
-
expect(@job2.reload.next_in_strand).to
|
557
|
-
expect(@job3.reload.next_in_strand).to
|
555
|
+
expect(@job1.reload.next_in_strand).to be true
|
556
|
+
expect(@job2.reload.next_in_strand).to be true
|
557
|
+
expect(@job3.reload.next_in_strand).to be false
|
558
558
|
|
559
559
|
@job2.destroy
|
560
|
-
expect(@job1.reload.next_in_strand).to
|
561
|
-
expect(@job3.reload.next_in_strand).to
|
560
|
+
expect(@job1.reload.next_in_strand).to be true
|
561
|
+
expect(@job3.reload.next_in_strand).to be true
|
562
562
|
end
|
563
563
|
|
564
564
|
it "does not violate n_strand=1 constraints when going from not stranded to stranded" do
|
@@ -568,13 +568,13 @@ shared_examples_for "a backend" do
|
|
568
568
|
Delayed::Job.get_and_lock_next_available("w1")
|
569
569
|
@job3 = create_job(singleton: "myjobs", strand: "myjobs")
|
570
570
|
|
571
|
-
expect(@job1.reload.next_in_strand).to
|
572
|
-
expect(@job2.reload.next_in_strand).to
|
573
|
-
expect(@job3.reload.next_in_strand).to
|
571
|
+
expect(@job1.reload.next_in_strand).to be true
|
572
|
+
expect(@job2.reload.next_in_strand).to be true
|
573
|
+
expect(@job3.reload.next_in_strand).to be false
|
574
574
|
|
575
575
|
@job2.destroy
|
576
|
-
expect(@job1.reload.next_in_strand).to
|
577
|
-
expect(@job3.reload.next_in_strand).to
|
576
|
+
expect(@job1.reload.next_in_strand).to be true
|
577
|
+
expect(@job3.reload.next_in_strand).to be false
|
578
578
|
end
|
579
579
|
|
580
580
|
it "handles transitions correctly when going from stranded to another strand" do
|
@@ -582,11 +582,11 @@ shared_examples_for "a backend" do
|
|
582
582
|
Delayed::Job.get_and_lock_next_available("w1")
|
583
583
|
@job2 = create_job(singleton: "myjobs", strand: "myjobs2")
|
584
584
|
|
585
|
-
expect(@job1.reload.next_in_strand).to
|
586
|
-
expect(@job2.reload.next_in_strand).to
|
585
|
+
expect(@job1.reload.next_in_strand).to be true
|
586
|
+
expect(@job2.reload.next_in_strand).to be false
|
587
587
|
|
588
588
|
@job1.destroy
|
589
|
-
expect(@job2.reload.next_in_strand).to
|
589
|
+
expect(@job2.reload.next_in_strand).to be true
|
590
590
|
end
|
591
591
|
|
592
592
|
it "does not violate n_strand=1 constraints when going from stranded to another strand" do
|
@@ -596,24 +596,24 @@ shared_examples_for "a backend" do
|
|
596
596
|
Delayed::Job.get_and_lock_next_available("w1")
|
597
597
|
@job3 = create_job(singleton: "myjobs", strand: "myjobs2")
|
598
598
|
|
599
|
-
expect(@job1.reload.next_in_strand).to
|
600
|
-
expect(@job2.reload.next_in_strand).to
|
601
|
-
expect(@job3.reload.next_in_strand).to
|
599
|
+
expect(@job1.reload.next_in_strand).to be true
|
600
|
+
expect(@job2.reload.next_in_strand).to be true
|
601
|
+
expect(@job3.reload.next_in_strand).to be false
|
602
602
|
|
603
603
|
@job2.destroy
|
604
|
-
expect(@job1.reload.next_in_strand).to
|
605
|
-
expect(@job3.reload.next_in_strand).to
|
604
|
+
expect(@job1.reload.next_in_strand).to be true
|
605
|
+
expect(@job3.reload.next_in_strand).to be false
|
606
606
|
end
|
607
607
|
|
608
608
|
it "creates first as true, and second as false, then transitions to second when deleted" do
|
609
609
|
@job1 = create_job(singleton: "myjobs")
|
610
610
|
Delayed::Job.get_and_lock_next_available("w1")
|
611
611
|
@job2 = create_job(singleton: "myjobs")
|
612
|
-
expect(@job1.reload.next_in_strand).to
|
613
|
-
expect(@job2.reload.next_in_strand).to
|
612
|
+
expect(@job1.reload.next_in_strand).to be true
|
613
|
+
expect(@job2.reload.next_in_strand).to be false
|
614
614
|
|
615
615
|
@job1.destroy
|
616
|
-
expect(@job2.reload.next_in_strand).to
|
616
|
+
expect(@job2.reload.next_in_strand).to be true
|
617
617
|
end
|
618
618
|
|
619
619
|
it "when combined with a strand" do
|
@@ -834,9 +834,9 @@ shared_examples_for "a backend" do
|
|
834
834
|
|
835
835
|
it "sets in_delayed_job?" do
|
836
836
|
job = InDelayedJobTest.delay(ignore_transaction: true).check_in_job
|
837
|
-
expect(Delayed::Job.in_delayed_job?).to
|
837
|
+
expect(Delayed::Job.in_delayed_job?).to be(false)
|
838
838
|
job.invoke_job
|
839
|
-
expect(Delayed::Job.in_delayed_job?).to
|
839
|
+
expect(Delayed::Job.in_delayed_job?).to be(false)
|
840
840
|
end
|
841
841
|
|
842
842
|
it "fails on job creation if an unsaved AR object is used" do
|
data/spec/shared/worker.rb
CHANGED
@@ -244,7 +244,7 @@ shared_examples_for "Delayed::Worker" do
|
|
244
244
|
end
|
245
245
|
|
246
246
|
it "is failed if it failed more than Settings.max_attempts times" do
|
247
|
-
expect(@job.failed_at).to
|
247
|
+
expect(@job.failed_at).to be_nil
|
248
248
|
Delayed::Settings.max_attempts.times { @job.reschedule }
|
249
249
|
expect(Delayed::Job.list_jobs(:failed, 100).size).to eq(1)
|
250
250
|
end
|
@@ -252,7 +252,7 @@ shared_examples_for "Delayed::Worker" do
|
|
252
252
|
it "is not failed if it failed fewer than Settings.max_attempts times" do
|
253
253
|
(Delayed::Settings.max_attempts - 1).times { @job.reschedule }
|
254
254
|
@job = Delayed::Job.find(@job.id)
|
255
|
-
expect(@job.failed_at).to
|
255
|
+
expect(@job.failed_at).to be_nil
|
256
256
|
end
|
257
257
|
|
258
258
|
it "is failed if it has expired" do
|
@@ -396,7 +396,7 @@ shared_examples_for "Delayed::Worker" do
|
|
396
396
|
expect(@worker).to receive(:exit?).and_return(true)
|
397
397
|
Delayed::Worker.lifecycle.before(:execute) { |w| w == @worker && fired = true }
|
398
398
|
@worker.start
|
399
|
-
expect(fired).to
|
399
|
+
expect(fired).to be(true)
|
400
400
|
end
|
401
401
|
end
|
402
402
|
|
data/spec/spec_helper.rb
CHANGED
@@ -55,14 +55,16 @@ connection_config = {
|
|
55
55
|
encoding: "utf8",
|
56
56
|
username: ENV["TEST_DB_USERNAME"],
|
57
57
|
database: ENV["TEST_DB_DATABASE"],
|
58
|
-
min_messages: "notice"
|
58
|
+
min_messages: "notice",
|
59
|
+
# Ensure the pool is big enough the deadlock tests don't get starved for connections by rails instead
|
60
|
+
pool: 20
|
59
61
|
}
|
60
62
|
|
61
63
|
def migrate(file)
|
62
64
|
ActiveRecord::MigrationContext.new(file, ActiveRecord::SchemaMigration).migrate
|
63
65
|
end
|
64
66
|
|
65
|
-
# create the test db if it does not exist
|
67
|
+
# create the test db if it does not exist
|
66
68
|
ActiveRecord::Base.establish_connection(connection_config.merge(database: "postgres"))
|
67
69
|
begin
|
68
70
|
ActiveRecord::Base.connection.create_database(connection_config[:database])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inst-jobs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2022-
|
13
|
+
date: 2022-03-30 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -32,14 +32,14 @@ dependencies:
|
|
32
32
|
requirements:
|
33
33
|
- - "~>"
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version:
|
35
|
+
version: 0.4.4
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
42
|
+
version: 0.4.4
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
44
|
name: activesupport
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -410,20 +410,6 @@ dependencies:
|
|
410
410
|
- - ">="
|
411
411
|
- !ruby/object:Gem::Version
|
412
412
|
version: '0'
|
413
|
-
- !ruby/object:Gem::Dependency
|
414
|
-
name: wwtd
|
415
|
-
requirement: !ruby/object:Gem::Requirement
|
416
|
-
requirements:
|
417
|
-
- - "~>"
|
418
|
-
- !ruby/object:Gem::Version
|
419
|
-
version: 1.4.0
|
420
|
-
type: :development
|
421
|
-
prerelease: false
|
422
|
-
version_requirements: !ruby/object:Gem::Requirement
|
423
|
-
requirements:
|
424
|
-
- - "~>"
|
425
|
-
- !ruby/object:Gem::Version
|
426
|
-
version: 1.4.0
|
427
413
|
description:
|
428
414
|
email:
|
429
415
|
- cody@instructure.com
|
@@ -473,6 +459,7 @@ files:
|
|
473
459
|
- db/migrate/20220128084800_update_insert_trigger_for_singleton_unique_constraint_change.rb
|
474
460
|
- db/migrate/20220128084900_update_delete_trigger_for_singleton_unique_constraint_change.rb
|
475
461
|
- db/migrate/20220203063200_remove_old_singleton_index.rb
|
462
|
+
- db/migrate/20220328152900_add_failed_jobs_indicies.rb
|
476
463
|
- exe/inst_jobs
|
477
464
|
- lib/delayed/backend/active_record.rb
|
478
465
|
- lib/delayed/backend/base.rb
|
@@ -538,7 +525,8 @@ files:
|
|
538
525
|
- spec/spec_helper.rb
|
539
526
|
homepage: https://github.com/instructure/inst-jobs
|
540
527
|
licenses: []
|
541
|
-
metadata:
|
528
|
+
metadata:
|
529
|
+
rubygems_mfa_required: 'true'
|
542
530
|
post_install_message:
|
543
531
|
rdoc_options: []
|
544
532
|
require_paths:
|
@@ -554,7 +542,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
554
542
|
- !ruby/object:Gem::Version
|
555
543
|
version: '0'
|
556
544
|
requirements: []
|
557
|
-
rubygems_version: 3.1.
|
545
|
+
rubygems_version: 3.1.6
|
558
546
|
signing_key:
|
559
547
|
specification_version: 4
|
560
548
|
summary: Instructure-maintained fork of delayed_job
|