inst-jobs 0.15.5 → 0.15.6
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
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 221663b9f3e3a49a829dd63a7f25b6eb8f558e3bdd594daf2e66e2adee996723
|
4
|
+
data.tar.gz: 14dd96fbad1a13b259761f4822e9f107537b6d16c92a9f1ceb5db0bb1f003e21
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 509766d3ede131621c056be6e95939d077dbdcdec2796217d4d53fdf8cb165d0e5a21a21a75b6bd3457d7de2b804b4786fa1b143377430825ddfd3a24fa2124b
|
7
|
+
data.tar.gz: eb31db5a091c2ff87e3d283a679830a0b77bbf85fc9b592ab988be7ca389e5c84a564d1ce021e7d87db9127d4f9b3885f4a17da24161d7949647e9da9a2dd480
|
@@ -0,0 +1,95 @@
|
|
1
|
+
class SpeedUpMaxConcurrentTriggers < ActiveRecord::Migration[4.2]
|
2
|
+
def connection
|
3
|
+
Delayed::Job.connection
|
4
|
+
end
|
5
|
+
|
6
|
+
def up
|
7
|
+
if connection.adapter_name == 'PostgreSQL'
|
8
|
+
# tl;dr sacrifice some responsiveness to max_concurrent changes for faster performance
|
9
|
+
# don't get the count every single time - it's usually safe to just set the next one in line
|
10
|
+
# since the max_concurrent doesn't change all that often for a strand
|
11
|
+
execute(<<-CODE)
|
12
|
+
CREATE OR REPLACE FUNCTION delayed_jobs_after_delete_row_tr_fn () RETURNS trigger AS $$
|
13
|
+
DECLARE
|
14
|
+
running_count integer;
|
15
|
+
BEGIN
|
16
|
+
IF OLD.strand IS NOT NULL THEN
|
17
|
+
PERFORM pg_advisory_xact_lock(half_md5_as_bigint(OLD.strand));
|
18
|
+
IF OLD.id % 20 = 0 THEN
|
19
|
+
running_count := (SELECT COUNT(*) FROM (
|
20
|
+
SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
|
21
|
+
) subquery_for_count);
|
22
|
+
IF running_count < OLD.max_concurrent THEN
|
23
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id IN (
|
24
|
+
SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
25
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT (OLD.max_concurrent - running_count) FOR UPDATE
|
26
|
+
);
|
27
|
+
END IF;
|
28
|
+
ELSE
|
29
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id =
|
30
|
+
(SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
31
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT 1 FOR UPDATE);
|
32
|
+
END IF;
|
33
|
+
END IF;
|
34
|
+
RETURN OLD;
|
35
|
+
END;
|
36
|
+
$$ LANGUAGE plpgsql;
|
37
|
+
CODE
|
38
|
+
|
39
|
+
# don't need the full count on insert
|
40
|
+
execute(<<-CODE)
|
41
|
+
CREATE OR REPLACE FUNCTION delayed_jobs_before_insert_row_tr_fn () RETURNS trigger AS $$
|
42
|
+
BEGIN
|
43
|
+
IF NEW.strand IS NOT NULL THEN
|
44
|
+
PERFORM pg_advisory_xact_lock(half_md5_as_bigint(NEW.strand));
|
45
|
+
IF (SELECT COUNT(*) FROM (
|
46
|
+
SELECT 1 AS one FROM delayed_jobs WHERE strand = NEW.strand LIMIT NEW.max_concurrent
|
47
|
+
) subquery_for_count) = NEW.max_concurrent THEN
|
48
|
+
NEW.next_in_strand := 'f';
|
49
|
+
END IF;
|
50
|
+
END IF;
|
51
|
+
RETURN NEW;
|
52
|
+
END;
|
53
|
+
$$ LANGUAGE plpgsql;
|
54
|
+
CODE
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def down
|
59
|
+
if connection.adapter_name == 'PostgreSQL'
|
60
|
+
execute(<<-CODE)
|
61
|
+
CREATE OR REPLACE FUNCTION delayed_jobs_after_delete_row_tr_fn () RETURNS trigger AS $$
|
62
|
+
DECLARE
|
63
|
+
running_count integer;
|
64
|
+
BEGIN
|
65
|
+
IF OLD.strand IS NOT NULL THEN
|
66
|
+
PERFORM pg_advisory_xact_lock(half_md5_as_bigint(OLD.strand));
|
67
|
+
running_count := (SELECT COUNT(*) FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't');
|
68
|
+
IF running_count < OLD.max_concurrent THEN
|
69
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id IN (
|
70
|
+
SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
71
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT (OLD.max_concurrent - running_count) FOR UPDATE
|
72
|
+
);
|
73
|
+
END IF;
|
74
|
+
END IF;
|
75
|
+
RETURN OLD;
|
76
|
+
END;
|
77
|
+
$$ LANGUAGE plpgsql;
|
78
|
+
CODE
|
79
|
+
|
80
|
+
execute(<<-CODE)
|
81
|
+
CREATE OR REPLACE FUNCTION delayed_jobs_before_insert_row_tr_fn () RETURNS trigger AS $$
|
82
|
+
BEGIN
|
83
|
+
IF NEW.strand IS NOT NULL THEN
|
84
|
+
PERFORM pg_advisory_xact_lock(half_md5_as_bigint(NEW.strand));
|
85
|
+
IF (SELECT COUNT(*) FROM delayed_jobs WHERE strand = NEW.strand) >= NEW.max_concurrent THEN
|
86
|
+
NEW.next_in_strand := 'f';
|
87
|
+
END IF;
|
88
|
+
END IF;
|
89
|
+
RETURN NEW;
|
90
|
+
END;
|
91
|
+
$$ LANGUAGE plpgsql;
|
92
|
+
CODE
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/delayed/version.rb
CHANGED
@@ -32,11 +32,15 @@ module Delayed
|
|
32
32
|
# prefetched jobs have their own way of automatically unlocking themselves
|
33
33
|
next if job.locked_by.start_with?("prefetch:")
|
34
34
|
unless live_workers.include?(job.locked_by)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
begin
|
36
|
+
Delayed::Job.transaction do
|
37
|
+
# double check that the job is still there. locked_by will immediately be reset
|
38
|
+
# to nil in this transaction by Job#reschedule
|
39
|
+
next unless Delayed::Job.where(id: job, locked_by: job.locked_by).update_all(locked_by: "abandoned job cleanup") == 1
|
40
|
+
job.reschedule
|
41
|
+
end
|
42
|
+
rescue
|
43
|
+
::Rails.logger.error "Failure rescheduling abandoned job #{job.id} #{$!.inspect}"
|
40
44
|
end
|
41
45
|
end
|
42
46
|
end
|
@@ -208,40 +208,6 @@ describe 'Delayed::Backed::ActiveRecord::Job' do
|
|
208
208
|
job3.next_in_strand.should == true
|
209
209
|
end
|
210
210
|
end
|
211
|
-
|
212
|
-
it "should set multiple jobs as next_in_strand at once if needed" do
|
213
|
-
change_setting(Delayed::Settings, :num_strands, ->(strand_name) {
|
214
|
-
case strand_name
|
215
|
-
when "njobs"; 2
|
216
|
-
else nil
|
217
|
-
end
|
218
|
-
}) do
|
219
|
-
job1 = Delayed::Job.enqueue(SimpleJob.new, n_strand: ["njobs"])
|
220
|
-
job1.reload
|
221
|
-
job1.next_in_strand.should == true
|
222
|
-
job2 = Delayed::Job.enqueue(SimpleJob.new, n_strand: ["njobs"])
|
223
|
-
job2.reload
|
224
|
-
job2.next_in_strand.should == true
|
225
|
-
|
226
|
-
job3 = Delayed::Job.enqueue(SimpleJob.new, n_strand: ["njobs"])
|
227
|
-
job3.reload
|
228
|
-
job3.next_in_strand.should == false
|
229
|
-
|
230
|
-
# manually unset next_in_strand
|
231
|
-
Delayed::Job.where(:id => job2).update_all(:next_in_strand => false)
|
232
|
-
job2.reload
|
233
|
-
job2.next_in_strand.should == false
|
234
|
-
|
235
|
-
run_job(job1) # should update both jobs
|
236
|
-
|
237
|
-
job3.reload
|
238
|
-
job3.next_in_strand.should == true
|
239
|
-
|
240
|
-
job2.reload
|
241
|
-
job2.next_in_strand.should == true
|
242
|
-
|
243
|
-
end
|
244
|
-
end
|
245
211
|
end
|
246
212
|
end
|
247
213
|
|
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: 0.15.
|
4
|
+
version: 0.15.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Luetke
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-06-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -346,6 +346,7 @@ files:
|
|
346
346
|
- db/migrate/20151123210429_add_expires_at_to_jobs.rb
|
347
347
|
- db/migrate/20151210162949_improve_max_concurrent.rb
|
348
348
|
- db/migrate/20161206323555_add_back_default_string_limits_jobs.rb
|
349
|
+
- db/migrate/20181217155351_speed_up_max_concurrent_triggers.rb
|
349
350
|
- exe/inst_jobs
|
350
351
|
- lib/delayed/backend/active_record.rb
|
351
352
|
- lib/delayed/backend/base.rb
|