inst-jobs 3.0.1 → 3.0.2

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: c9d86b7b6161b9397c885a82d687f85d84e7a17db5261bfc5ef1bb7e9f25e2ac
4
- data.tar.gz: 4a75f8ac73b5f0a0b19d8073bcbfe87f654bbbdb90e147ddf02066916653d4e0
3
+ metadata.gz: 55850c386085b90bbb9df7ff954d40ed7f2035268860ec8b47dfc11f11ec7e51
4
+ data.tar.gz: 53065a1f09e8cd30271bc9b57ab58d3bcfff8cf1b9590568379427093de9cbe9
5
5
  SHA512:
6
- metadata.gz: cd3f9df169146f34f7366e02830575bf27e2fd33e97d190bed34dd8be44e34431261111eef133368cd342668cabeb529af6e16c8985fcf15c99807ea7a07fbab
7
- data.tar.gz: 3924f7b2f6f4eee37c4d92bfedfd683304dfd0c035a65f47ea9dae607c0e81b03c35860420f39a7dadf890d203c85fe24de68c90c80a48839f23b6193311b3e3
6
+ metadata.gz: 8f7d579cddb80890c6158a1384f6828ae91272a864308528ad84e6dc47b3e4769062f91de7ebf9641f4b766c21c571a419385ee57bec9b6e5531f39be30a50a8
7
+ data.tar.gz: 887648362dec636b3e1f6938e66dd25b97f42a3e606c5d8466768d5b2ed5137ea50b67c68ce9ec817df86f117ef0660f6ddd3456c86e4871965f89704cc161f3
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UpdateAfterDeleteTriggerForSingletonIndex < ActiveRecord::Migration[6.0]
4
+ def up
5
+ execute(<<~SQL)
6
+ CREATE OR REPLACE FUNCTION delayed_jobs_after_delete_row_tr_fn () RETURNS trigger AS $$
7
+ DECLARE
8
+ running_count integer;
9
+ should_lock boolean;
10
+ should_be_precise boolean;
11
+ update_query varchar;
12
+ skip_locked varchar;
13
+ BEGIN
14
+ IF OLD.strand IS NOT NULL THEN
15
+ should_lock := true;
16
+ should_be_precise := OLD.id % (OLD.max_concurrent * 4) = 0;
17
+
18
+ IF NOT should_be_precise AND OLD.max_concurrent > 16 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
+ should_lock := running_count < OLD.max_concurrent;
23
+ END IF;
24
+
25
+ IF should_lock THEN
26
+ PERFORM pg_advisory_xact_lock(half_md5_as_bigint(OLD.strand));
27
+ END IF;
28
+
29
+ -- note that we don't really care if the row we're deleting has a singleton, or if it even
30
+ -- matches the row(s) we're going to update. we just need to make sure that whatever
31
+ -- singleton we grab isn't already running (which is a simple existence check, since
32
+ -- the unique indexes ensure there is at most one singleton running, and one queued)
33
+ update_query := 'UPDATE delayed_jobs SET next_in_strand=true WHERE id IN (
34
+ SELECT id FROM delayed_jobs j2
35
+ WHERE next_in_strand=false AND
36
+ j2.strand=$1.strand AND
37
+ (j2.singleton IS NULL OR NOT EXISTS (SELECT 1 FROM delayed_jobs j3 WHERE j3.singleton=j2.singleton AND j3.id<>j2.id AND (j3.locked_by IS NULL OR j3.locked_by IS NOT NULL)))
38
+ ORDER BY j2.strand_order_override ASC, j2.id ASC
39
+ LIMIT ';
40
+
41
+ IF should_be_precise THEN
42
+ running_count := (SELECT COUNT(*) FROM (
43
+ SELECT 1 FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
44
+ ) s);
45
+ IF running_count < OLD.max_concurrent THEN
46
+ update_query := update_query || '($1.max_concurrent - $2)';
47
+ ELSE
48
+ -- we have too many running already; just bail
49
+ RETURN OLD;
50
+ END IF;
51
+ ELSE
52
+ update_query := update_query || '1';
53
+
54
+ -- n-strands don't require precise ordering; we can make this query more performant
55
+ IF OLD.max_concurrent > 1 THEN
56
+ skip_locked := ' SKIP LOCKED';
57
+ END IF;
58
+ END IF;
59
+
60
+ update_query := update_query || ' FOR UPDATE' || COALESCE(skip_locked, '') || ')';
61
+ EXECUTE update_query USING OLD, running_count;
62
+ ELSIF OLD.singleton IS NOT NULL THEN
63
+ UPDATE delayed_jobs SET next_in_strand = 't' WHERE singleton=OLD.singleton AND next_in_strand=false AND locked_by IS NULL;
64
+ END IF;
65
+ RETURN OLD;
66
+ END;
67
+ $$ LANGUAGE plpgsql;
68
+ SQL
69
+ end
70
+
71
+ def down
72
+ execute(<<~SQL)
73
+ CREATE OR REPLACE FUNCTION delayed_jobs_after_delete_row_tr_fn () RETURNS trigger AS $$
74
+ DECLARE
75
+ running_count integer;
76
+ should_lock boolean;
77
+ should_be_precise boolean;
78
+ update_query varchar;
79
+ skip_locked varchar;
80
+ BEGIN
81
+ IF OLD.strand IS NOT NULL THEN
82
+ should_lock := true;
83
+ should_be_precise := OLD.id % (OLD.max_concurrent * 4) = 0;
84
+
85
+ IF NOT should_be_precise AND OLD.max_concurrent > 16 THEN
86
+ running_count := (SELECT COUNT(*) FROM (
87
+ SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
88
+ ) subquery_for_count);
89
+ should_lock := running_count < OLD.max_concurrent;
90
+ END IF;
91
+
92
+ IF should_lock THEN
93
+ PERFORM pg_advisory_xact_lock(half_md5_as_bigint(OLD.strand));
94
+ END IF;
95
+
96
+ -- note that we don't really care if the row we're deleting has a singleton, or if it even
97
+ -- matches the row(s) we're going to update. we just need to make sure that whatever
98
+ -- singleton we grab isn't already running (which is a simple existence check, since
99
+ -- the unique indexes ensure there is at most one singleton running, and one queued)
100
+ update_query := 'UPDATE delayed_jobs SET next_in_strand=true WHERE id IN (
101
+ SELECT id FROM delayed_jobs j2
102
+ WHERE next_in_strand=false AND
103
+ j2.strand=$1.strand AND
104
+ (j2.singleton IS NULL OR NOT EXISTS (SELECT 1 FROM delayed_jobs j3 WHERE j3.singleton=j2.singleton AND j3.id<>j2.id))
105
+ ORDER BY j2.strand_order_override ASC, j2.id ASC
106
+ LIMIT ';
107
+
108
+ IF should_be_precise THEN
109
+ running_count := (SELECT COUNT(*) FROM (
110
+ SELECT 1 FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
111
+ ) s);
112
+ IF running_count < OLD.max_concurrent THEN
113
+ update_query := update_query || '($1.max_concurrent - $2)';
114
+ ELSE
115
+ -- we have too many running already; just bail
116
+ RETURN OLD;
117
+ END IF;
118
+ ELSE
119
+ update_query := update_query || '1';
120
+
121
+ -- n-strands don't require precise ordering; we can make this query more performant
122
+ IF OLD.max_concurrent > 1 THEN
123
+ skip_locked := ' SKIP LOCKED';
124
+ END IF;
125
+ END IF;
126
+
127
+ update_query := update_query || ' FOR UPDATE' || COALESCE(skip_locked, '') || ')';
128
+ EXECUTE update_query USING OLD, running_count;
129
+ ELSIF OLD.singleton IS NOT NULL THEN
130
+ UPDATE delayed_jobs SET next_in_strand = 't' WHERE singleton=OLD.singleton AND next_in_strand=false;
131
+ END IF;
132
+ RETURN OLD;
133
+ END;
134
+ $$ LANGUAGE plpgsql;
135
+ SQL
136
+ end
137
+ end
@@ -309,7 +309,7 @@ module Delayed
309
309
  if Settings.silence_periodic_log
310
310
  ::ActiveRecord::Base.logger.silence(&block)
311
311
  else
312
- block.call
312
+ yield
313
313
  end
314
314
  end
315
315
 
@@ -548,7 +548,7 @@ module Delayed
548
548
 
549
549
  def fail!
550
550
  attrs = attributes
551
- attrs["original_job_id"] = attrs.delete("id")
551
+ attrs["original_job_id"] = attrs.delete("id") if Failed.columns_hash.key?("original_job_id")
552
552
  attrs["failed_at"] ||= self.class.db_time_now
553
553
  attrs.delete("next_in_strand")
554
554
  attrs.delete("max_concurrent")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delayed
4
- VERSION = "3.0.1"
4
+ VERSION = "3.0.2"
5
5
  end
@@ -5,10 +5,10 @@ module Delayed
5
5
  module ProcessHelper
6
6
  STAT_LINUX = "stat --format=%%Y /proc/$WORKER_PID"
7
7
  STAT_MAC = "ps -o lstart -p $WORKER_PID"
8
- STAT = RUBY_PLATFORM =~ /darwin/ ? STAT_MAC : STAT_LINUX
8
+ STAT = RUBY_PLATFORM.include?("darwin") ? STAT_MAC : STAT_LINUX
9
9
  ALIVE_CHECK_LINUX = '[ -d "/proc/$WORKER_PID" ]'
10
10
  ALIVE_CHECK_MAC = "ps -p $WORKER_PID > /dev/null"
11
- ALIVE_CHECK = RUBY_PLATFORM =~ /darwin/ ? ALIVE_CHECK_MAC : ALIVE_CHECK_LINUX
11
+ ALIVE_CHECK = RUBY_PLATFORM.include?("darwin") ? ALIVE_CHECK_MAC : ALIVE_CHECK_LINUX
12
12
  SCRIPT_TEMPLATE = <<-BASH
13
13
  WORKER_PID="%<pid>d" # an example, filled from ruby when the check is created
14
14
  ORIGINAL_MTIME="%<mtime>s" # an example, filled from ruby when the check is created
@@ -29,7 +29,7 @@ module Delayed
29
29
  BASH
30
30
 
31
31
  def self.mtime(pid)
32
- if RUBY_PLATFORM =~ /darwin/
32
+ if RUBY_PLATFORM.include?("darwin")
33
33
  `ps -o lstart -p #{pid}`.sub(/\n$/, "").presence
34
34
  else
35
35
  File::Stat.new("/proc/#{pid}").mtime.to_i.to_s rescue nil
@@ -219,14 +219,14 @@ describe "Delayed::Backed::ActiveRecord::Job" do
219
219
  end
220
220
 
221
221
  it "gets process ids from locked_by" do
222
- 3.times.map { Delayed::Job.create payload_object: SimpleJob.new }
222
+ Array.new(3) { Delayed::Job.create payload_object: SimpleJob.new }
223
223
  Delayed::Job.get_and_lock_next_available(["job42:2", "job42:9001"])
224
224
  expect(Delayed::Job.processes_locked_locally(name: "job42").sort).to eq [2, 9001]
225
225
  expect(Delayed::Job.processes_locked_locally(name: "jobnotme")).to be_empty
226
226
  end
227
227
 
228
228
  it "allows fetching multiple jobs at once" do
229
- jobs = 3.times.map { Delayed::Job.create payload_object: SimpleJob.new }
229
+ jobs = Array.new(3) { Delayed::Job.create payload_object: SimpleJob.new }
230
230
  locked_jobs = Delayed::Job.get_and_lock_next_available(%w[worker1 worker2])
231
231
  expect(locked_jobs.length).to eq(2)
232
232
  expect(locked_jobs.keys).to eq(%w[worker1 worker2])
@@ -235,7 +235,7 @@ describe "Delayed::Backed::ActiveRecord::Job" do
235
235
  end
236
236
 
237
237
  it "allows fetching extra jobs" do
238
- jobs = 5.times.map { Delayed::Job.create payload_object: SimpleJob.new }
238
+ jobs = Array.new(5) { Delayed::Job.create payload_object: SimpleJob.new }
239
239
  locked_jobs = Delayed::Job.get_and_lock_next_available(["worker1"],
240
240
  prefetch: 2,
241
241
  prefetch_owner: "work_queue")
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inst-jobs
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
8
8
  - Ethan Vizitei
9
9
  - Jacob Burroughs
10
- autorequire:
10
+ autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2021-10-20 00:00:00.000000000 Z
13
+ date: 2021-11-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -298,6 +298,20 @@ dependencies:
298
298
  - - "~>"
299
299
  - !ruby/object:Gem::Version
300
300
  version: '1.19'
301
+ - !ruby/object:Gem::Dependency
302
+ name: rubocop-performance
303
+ requirement: !ruby/object:Gem::Requirement
304
+ requirements:
305
+ - - "~>"
306
+ - !ruby/object:Gem::Version
307
+ version: 1.12.0
308
+ type: :development
309
+ prerelease: false
310
+ version_requirements: !ruby/object:Gem::Requirement
311
+ requirements:
312
+ - - "~>"
313
+ - !ruby/object:Gem::Version
314
+ version: 1.12.0
301
315
  - !ruby/object:Gem::Dependency
302
316
  name: rubocop-rails
303
317
  requirement: !ruby/object:Gem::Requirement
@@ -410,7 +424,7 @@ dependencies:
410
424
  - - "~>"
411
425
  - !ruby/object:Gem::Version
412
426
  version: 1.4.0
413
- description:
427
+ description:
414
428
  email:
415
429
  - cody@instructure.com
416
430
  - evizitei@instructure.com
@@ -451,6 +465,7 @@ files:
451
465
  - db/migrate/20210917232626_add_delete_conflicting_singletons_before_unlock_trigger.rb
452
466
  - db/migrate/20210928174754_fix_singleton_condition_in_before_insert.rb
453
467
  - db/migrate/20210929204903_update_conflicting_singleton_function_to_use_index.rb
468
+ - db/migrate/20211101190934_update_after_delete_trigger_for_singleton_index.rb
454
469
  - exe/inst_jobs
455
470
  - lib/delayed/backend/active_record.rb
456
471
  - lib/delayed/backend/base.rb
@@ -516,7 +531,7 @@ files:
516
531
  homepage: https://github.com/instructure/inst-jobs
517
532
  licenses: []
518
533
  metadata: {}
519
- post_install_message:
534
+ post_install_message:
520
535
  rdoc_options: []
521
536
  require_paths:
522
537
  - lib
@@ -531,8 +546,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
531
546
  - !ruby/object:Gem::Version
532
547
  version: '0'
533
548
  requirements: []
534
- rubygems_version: 3.0.3
535
- signing_key:
549
+ rubygems_version: 3.2.24
550
+ signing_key:
536
551
  specification_version: 4
537
552
  summary: Instructure-maintained fork of delayed_job
538
553
  test_files: