switchman-inst-jobs 3.2.10 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/db/migrate/20101216224513_create_delayed_jobs.rb +1 -1
  3. data/db/migrate/20110208031356_add_delayed_jobs_tag.rb +1 -1
  4. data/db/migrate/20110426161613_add_delayed_jobs_max_attempts.rb +1 -1
  5. data/db/migrate/20110516225834_add_delayed_jobs_strand.rb +1 -1
  6. data/db/migrate/20110531144916_cleanup_delayed_jobs_indexes.rb +1 -1
  7. data/db/migrate/20110610213249_optimize_delayed_jobs.rb +1 -1
  8. data/db/migrate/20110831210257_add_delayed_jobs_next_in_strand.rb +1 -1
  9. data/db/migrate/20120510004759_delayed_jobs_delete_trigger_lock_for_update.rb +1 -1
  10. data/db/migrate/20120531150712_drop_psql_jobs_pop_fn.rb +1 -1
  11. data/db/migrate/20120607164022_delayed_jobs_use_advisory_locks.rb +1 -1
  12. data/db/migrate/20120607181141_index_jobs_on_locked_by.rb +2 -2
  13. data/db/migrate/20120608191051_add_jobs_run_at_index.rb +2 -2
  14. data/db/migrate/20120927184213_change_delayed_jobs_handler_to_text.rb +1 -1
  15. data/db/migrate/20140505215131_add_failed_jobs_original_job_id.rb +1 -1
  16. data/db/migrate/20140505215510_copy_failed_jobs_original_id.rb +2 -2
  17. data/db/migrate/20140505223637_drop_failed_jobs_original_id.rb +1 -1
  18. data/db/migrate/20140512213941_add_source_to_jobs.rb +1 -1
  19. data/db/migrate/20150807133223_add_max_concurrent_to_jobs.rb +1 -1
  20. data/db/migrate/20151123210429_add_expires_at_to_jobs.rb +1 -1
  21. data/db/migrate/20151210162949_improve_max_concurrent.rb +1 -1
  22. data/db/migrate/20161206323555_add_back_default_string_limits_jobs.rb +1 -1
  23. data/db/migrate/20170308045400_add_shard_id_to_delayed_jobs.rb +1 -11
  24. data/db/migrate/20170308045401_add_delayed_jobs_shard_id_to_switchman_shards.rb +5 -0
  25. data/db/migrate/20181217155351_speed_up_max_concurrent_triggers.rb +1 -1
  26. data/db/migrate/20190726154743_make_critical_columns_not_null.rb +1 -1
  27. data/db/migrate/20200330230722_add_id_to_get_delayed_jobs_index.rb +2 -2
  28. data/db/migrate/20200824222232_speed_up_max_concurrent_delete_trigger.rb +1 -1
  29. data/db/migrate/20200825011002_add_strand_order_override.rb +2 -2
  30. data/lib/switchman_inst_jobs/active_record/connection_adapters/connection_pool.rb +15 -0
  31. data/lib/switchman_inst_jobs/delayed/backend/base.rb +10 -9
  32. data/lib/switchman_inst_jobs/delayed/pool.rb +1 -1
  33. data/lib/switchman_inst_jobs/delayed/worker/health_check.rb +10 -12
  34. data/lib/switchman_inst_jobs/delayed/worker.rb +2 -2
  35. data/lib/switchman_inst_jobs/engine.rb +8 -10
  36. data/lib/switchman_inst_jobs/jobs_migrator.rb +88 -144
  37. data/lib/switchman_inst_jobs/switchman/shard.rb +8 -21
  38. data/lib/switchman_inst_jobs/version.rb +1 -1
  39. data/lib/switchman_inst_jobs.rb +8 -0
  40. metadata +44 -51
  41. data/db/migrate/20210809145804_add_n_strand_index.rb +0 -12
  42. data/db/migrate/20210812210128_add_singleton_column.rb +0 -200
  43. data/db/migrate/20210917232626_add_delete_conflicting_singletons_before_unlock_trigger.rb +0 -27
  44. data/db/migrate/20210928174754_fix_singleton_condition_in_before_insert.rb +0 -56
  45. data/db/migrate/20210929204903_update_conflicting_singleton_function_to_use_index.rb +0 -27
  46. data/db/migrate/20211101190934_update_after_delete_trigger_for_singleton_index.rb +0 -137
  47. data/db/migrate/20211207094200_update_after_delete_trigger_for_singleton_transition_cases.rb +0 -171
  48. data/db/migrate/20211220112800_fix_singleton_race_condition_insert.rb +0 -59
  49. data/db/migrate/20211220113000_fix_singleton_race_condition_delete.rb +0 -207
  50. data/db/migrate/20220127091200_fix_singleton_unique_constraint.rb +0 -31
  51. data/db/migrate/20220128084800_update_insert_trigger_for_singleton_unique_constraint_change.rb +0 -60
  52. data/db/migrate/20220128084900_update_delete_trigger_for_singleton_unique_constraint_change.rb +0 -209
  53. data/db/migrate/20220203063200_remove_old_singleton_index.rb +0 -31
metadata CHANGED
@@ -1,35 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switchman-inst-jobs
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.10
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bryan Petty
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-23 00:00:00.000000000 Z
11
+ date: 2021-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: inst-jobs
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.4.9
20
- - - "<"
19
+ version: '2.0'
20
+ - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: '4.0'
22
+ version: 2.3.1
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
- - - ">="
27
+ - - "~>"
28
28
  - !ruby/object:Gem::Version
29
- version: 2.4.9
30
- - - "<"
29
+ version: '2.0'
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: '4.0'
32
+ version: 2.3.1
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: parallel
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -50,34 +50,40 @@ dependencies:
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: '5.2'
53
+ version: '6.1'
54
54
  - - "<"
55
55
  - !ruby/object:Gem::Version
56
- version: '6.1'
56
+ version: '6.2'
57
57
  type: :runtime
58
58
  prerelease: false
59
59
  version_requirements: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - ">="
62
62
  - !ruby/object:Gem::Version
63
- version: '5.2'
63
+ version: '6.1'
64
64
  - - "<"
65
65
  - !ruby/object:Gem::Version
66
- version: '6.1'
66
+ version: '6.2'
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: switchman
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: '2.0'
73
+ version: '3.0'
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 3.0.1
74
77
  type: :runtime
75
78
  prerelease: false
76
79
  version_requirements: !ruby/object:Gem::Requirement
77
80
  requirements:
78
81
  - - "~>"
79
82
  - !ruby/object:Gem::Version
80
- version: '2.0'
83
+ version: '3.0'
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 3.0.1
81
87
  - !ruby/object:Gem::Dependency
82
88
  name: bundler
83
89
  requirement: !ruby/object:Gem::Requirement
@@ -110,16 +116,16 @@ dependencies:
110
116
  name: diplomat
111
117
  requirement: !ruby/object:Gem::Requirement
112
118
  requirements:
113
- - - ">="
119
+ - - "~>"
114
120
  - !ruby/object:Gem::Version
115
- version: '0'
121
+ version: 2.5.1
116
122
  type: :development
117
123
  prerelease: false
118
124
  version_requirements: !ruby/object:Gem::Requirement
119
125
  requirements:
120
- - - ">="
126
+ - - "~>"
121
127
  - !ruby/object:Gem::Version
122
- version: '0'
128
+ version: 2.5.1
123
129
  - !ruby/object:Gem::Dependency
124
130
  name: newrelic_rpm
125
131
  requirement: !ruby/object:Gem::Requirement
@@ -182,70 +188,70 @@ dependencies:
182
188
  requirements:
183
189
  - - "~>"
184
190
  - !ruby/object:Gem::Version
185
- version: '3.6'
191
+ version: '3.10'
186
192
  type: :development
187
193
  prerelease: false
188
194
  version_requirements: !ruby/object:Gem::Requirement
189
195
  requirements:
190
196
  - - "~>"
191
197
  - !ruby/object:Gem::Version
192
- version: '3.6'
198
+ version: '3.10'
193
199
  - !ruby/object:Gem::Dependency
194
200
  name: rspec-rails
195
201
  requirement: !ruby/object:Gem::Requirement
196
202
  requirements:
197
203
  - - "~>"
198
204
  - !ruby/object:Gem::Version
199
- version: '3.6'
205
+ version: '5.0'
200
206
  type: :development
201
207
  prerelease: false
202
208
  version_requirements: !ruby/object:Gem::Requirement
203
209
  requirements:
204
210
  - - "~>"
205
211
  - !ruby/object:Gem::Version
206
- version: '3.6'
212
+ version: '5.0'
207
213
  - !ruby/object:Gem::Dependency
208
214
  name: rubocop
209
215
  requirement: !ruby/object:Gem::Requirement
210
216
  requirements:
211
217
  - - "~>"
212
218
  - !ruby/object:Gem::Version
213
- version: 1.3.1
219
+ version: '1.15'
214
220
  type: :development
215
221
  prerelease: false
216
222
  version_requirements: !ruby/object:Gem::Requirement
217
223
  requirements:
218
224
  - - "~>"
219
225
  - !ruby/object:Gem::Version
220
- version: 1.3.1
226
+ version: '1.15'
221
227
  - !ruby/object:Gem::Dependency
222
228
  name: rubocop-rails
223
229
  requirement: !ruby/object:Gem::Requirement
224
230
  requirements:
225
231
  - - "~>"
226
232
  - !ruby/object:Gem::Version
227
- version: 2.8.1
233
+ version: '2.10'
228
234
  type: :development
229
235
  prerelease: false
230
236
  version_requirements: !ruby/object:Gem::Requirement
231
237
  requirements:
232
238
  - - "~>"
233
239
  - !ruby/object:Gem::Version
234
- version: 2.8.1
240
+ version: '2.10'
235
241
  - !ruby/object:Gem::Dependency
236
242
  name: simplecov
237
243
  requirement: !ruby/object:Gem::Requirement
238
244
  requirements:
239
245
  - - "~>"
240
246
  - !ruby/object:Gem::Version
241
- version: '0.18'
247
+ version: '0.21'
242
248
  type: :development
243
249
  prerelease: false
244
250
  version_requirements: !ruby/object:Gem::Requirement
245
251
  requirements:
246
252
  - - "~>"
247
253
  - !ruby/object:Gem::Version
248
- version: '0.18'
254
+ version: '0.21'
249
255
  - !ruby/object:Gem::Dependency
250
256
  name: wwtd
251
257
  requirement: !ruby/object:Gem::Requirement
@@ -260,7 +266,7 @@ dependencies:
260
266
  - - "~>"
261
267
  - !ruby/object:Gem::Version
262
268
  version: '1.4'
263
- description:
269
+ description:
264
270
  email:
265
271
  - bpetty@instructure.com
266
272
  executables: []
@@ -289,6 +295,7 @@ files:
289
295
  - db/migrate/20151210162949_improve_max_concurrent.rb
290
296
  - db/migrate/20161206323555_add_back_default_string_limits_jobs.rb
291
297
  - db/migrate/20170308045400_add_shard_id_to_delayed_jobs.rb
298
+ - db/migrate/20170308045401_add_delayed_jobs_shard_id_to_switchman_shards.rb
292
299
  - db/migrate/20181217155351_speed_up_max_concurrent_triggers.rb
293
300
  - db/migrate/20190726154743_make_critical_columns_not_null.rb
294
301
  - db/migrate/20200330230722_add_id_to_get_delayed_jobs_index.rb
@@ -296,21 +303,9 @@ files:
296
303
  - db/migrate/20200822014259_add_block_stranded_to_switchman_shards.rb
297
304
  - db/migrate/20200824222232_speed_up_max_concurrent_delete_trigger.rb
298
305
  - db/migrate/20200825011002_add_strand_order_override.rb
299
- - db/migrate/20210809145804_add_n_strand_index.rb
300
- - db/migrate/20210812210128_add_singleton_column.rb
301
- - db/migrate/20210917232626_add_delete_conflicting_singletons_before_unlock_trigger.rb
302
- - db/migrate/20210928174754_fix_singleton_condition_in_before_insert.rb
303
- - db/migrate/20210929204903_update_conflicting_singleton_function_to_use_index.rb
304
- - db/migrate/20211101190934_update_after_delete_trigger_for_singleton_index.rb
305
- - db/migrate/20211207094200_update_after_delete_trigger_for_singleton_transition_cases.rb
306
- - db/migrate/20211220112800_fix_singleton_race_condition_insert.rb
307
- - db/migrate/20211220113000_fix_singleton_race_condition_delete.rb
308
- - db/migrate/20220127091200_fix_singleton_unique_constraint.rb
309
- - db/migrate/20220128084800_update_insert_trigger_for_singleton_unique_constraint_change.rb
310
- - db/migrate/20220128084900_update_delete_trigger_for_singleton_unique_constraint_change.rb
311
- - db/migrate/20220203063200_remove_old_singleton_index.rb
312
306
  - lib/switchman-inst-jobs.rb
313
307
  - lib/switchman_inst_jobs.rb
308
+ - lib/switchman_inst_jobs/active_record/connection_adapters/connection_pool.rb
314
309
  - lib/switchman_inst_jobs/active_record/connection_adapters/postgresql_adapter.rb
315
310
  - lib/switchman_inst_jobs/active_record/migration.rb
316
311
  - lib/switchman_inst_jobs/delayed/backend/base.rb
@@ -332,10 +327,8 @@ files:
332
327
  homepage: https://github.com/instructure/switchman-inst-jobs
333
328
  licenses:
334
329
  - MIT
335
- metadata:
336
- allowed_push_host: https://rubygems.org
337
- rubygems_mfa_required: 'true'
338
- post_install_message:
330
+ metadata: {}
331
+ post_install_message:
339
332
  rdoc_options: []
340
333
  require_paths:
341
334
  - lib
@@ -350,8 +343,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
350
343
  - !ruby/object:Gem::Version
351
344
  version: '0'
352
345
  requirements: []
353
- rubygems_version: 3.1.4
354
- signing_key:
346
+ rubygems_version: 3.2.15
347
+ signing_key:
355
348
  specification_version: 4
356
349
  summary: Switchman and Instructure Jobs compatibility gem.
357
350
  test_files: []
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class AddNStrandIndex < ActiveRecord::Migration[5.2]
4
- disable_ddl_transaction!
5
-
6
- def change
7
- add_index :delayed_jobs, %i[strand next_in_strand id],
8
- name: 'n_strand_index',
9
- where: 'strand IS NOT NULL',
10
- algorithm: :concurrently
11
- end
12
- end
@@ -1,200 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class AddSingletonColumn < ActiveRecord::Migration[5.2]
4
- disable_ddl_transaction!
5
-
6
- def change
7
- add_column :delayed_jobs, :singleton, :string, if_not_exists: true
8
- add_column :failed_jobs, :singleton, :string, if_not_exists: true
9
- # only one job can be queued in a singleton
10
- add_index :delayed_jobs,
11
- :singleton,
12
- where: 'singleton IS NOT NULL AND locked_by IS NULL',
13
- unique: true,
14
- name: 'index_delayed_jobs_on_singleton_not_running',
15
- algorithm: :concurrently
16
- # only one job can be running for a singleton
17
- add_index :delayed_jobs,
18
- :singleton,
19
- where: 'singleton IS NOT NULL AND locked_by IS NOT NULL',
20
- unique: true,
21
- name: 'index_delayed_jobs_on_singleton_running',
22
- algorithm: :concurrently
23
-
24
- reversible do |direction|
25
- direction.up do
26
- execute(<<~SQL)
27
- CREATE OR REPLACE FUNCTION #{connection.quote_table_name('delayed_jobs_after_delete_row_tr_fn')} () RETURNS trigger AS $$
28
- DECLARE
29
- running_count integer;
30
- should_lock boolean;
31
- should_be_precise boolean;
32
- update_query varchar;
33
- skip_locked varchar;
34
- BEGIN
35
- IF OLD.strand IS NOT NULL THEN
36
- should_lock := true;
37
- should_be_precise := OLD.id % (OLD.max_concurrent * 4) = 0;
38
-
39
- IF NOT should_be_precise AND OLD.max_concurrent > 16 THEN
40
- running_count := (SELECT COUNT(*) FROM (
41
- SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
42
- ) subquery_for_count);
43
- should_lock := running_count < OLD.max_concurrent;
44
- END IF;
45
-
46
- IF should_lock THEN
47
- PERFORM pg_advisory_xact_lock(half_md5_as_bigint(OLD.strand));
48
- END IF;
49
-
50
- -- note that we don't really care if the row we're deleting has a singleton, or if it even
51
- -- matches the row(s) we're going to update. we just need to make sure that whatever
52
- -- singleton we grab isn't already running (which is a simple existence check, since
53
- -- the unique indexes ensure there is at most one singleton running, and one queued)
54
- update_query := 'UPDATE delayed_jobs SET next_in_strand=true WHERE id IN (
55
- SELECT id FROM delayed_jobs j2
56
- WHERE next_in_strand=false AND
57
- j2.strand=$1.strand AND
58
- (j2.singleton IS NULL OR NOT EXISTS (SELECT 1 FROM delayed_jobs j3 WHERE j3.singleton=j2.singleton AND j3.id<>j2.id))
59
- ORDER BY j2.strand_order_override ASC, j2.id ASC
60
- LIMIT ';
61
-
62
- IF should_be_precise THEN
63
- running_count := (SELECT COUNT(*) FROM (
64
- SELECT 1 FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
65
- ) s);
66
- IF running_count < OLD.max_concurrent THEN
67
- update_query := update_query || '($1.max_concurrent - $2)';
68
- ELSE
69
- -- we have too many running already; just bail
70
- RETURN OLD;
71
- END IF;
72
- ELSE
73
- update_query := update_query || '1';
74
-
75
- -- n-strands don't require precise ordering; we can make this query more performant
76
- IF OLD.max_concurrent > 1 THEN
77
- skip_locked := ' SKIP LOCKED';
78
- END IF;
79
- END IF;
80
-
81
- update_query := update_query || ' FOR UPDATE' || COALESCE(skip_locked, '') || ')';
82
- EXECUTE update_query USING OLD, running_count;
83
- ELSIF OLD.singleton IS NOT NULL THEN
84
- UPDATE delayed_jobs SET next_in_strand = 't' WHERE singleton=OLD.singleton AND next_in_strand=false;
85
- END IF;
86
- RETURN OLD;
87
- END;
88
- $$ LANGUAGE plpgsql SET search_path TO #{::Switchman::Shard.current.name};
89
- SQL
90
- execute(<<~SQL)
91
- CREATE OR REPLACE FUNCTION #{connection.quote_table_name('delayed_jobs_before_insert_row_tr_fn')} () RETURNS trigger AS $$
92
- BEGIN
93
- IF NEW.strand IS NOT NULL THEN
94
- PERFORM pg_advisory_xact_lock(half_md5_as_bigint(NEW.strand));
95
- IF (SELECT COUNT(*) FROM (
96
- SELECT 1 FROM delayed_jobs WHERE strand = NEW.strand AND next_in_strand=true LIMIT NEW.max_concurrent
97
- ) s) = NEW.max_concurrent THEN
98
- NEW.next_in_strand := false;
99
- END IF;
100
- END IF;
101
- IF NEW.singleton IS NOT NULL THEN
102
- PERFORM 1 FROM delayed_jobs WHERE singleton = NEW.singleton;
103
- IF FOUND THEN
104
- NEW.next_in_strand := false;
105
- END IF;
106
- END IF;
107
- RETURN NEW;
108
- END;
109
- $$ LANGUAGE plpgsql SET search_path TO #{::Switchman::Shard.current.name};
110
- SQL
111
- end
112
- direction.down do
113
- execute(<<~SQL)
114
- CREATE OR REPLACE FUNCTION #{connection.quote_table_name('delayed_jobs_after_delete_row_tr_fn')} () RETURNS trigger AS $$
115
- DECLARE
116
- running_count integer;
117
- should_lock boolean;
118
- should_be_precise boolean;
119
- BEGIN
120
- IF OLD.strand IS NOT NULL THEN
121
- should_lock := true;
122
- should_be_precise := OLD.id % (OLD.max_concurrent * 4) = 0;
123
-
124
- IF NOT should_be_precise AND OLD.max_concurrent > 16 THEN
125
- running_count := (SELECT COUNT(*) FROM (
126
- SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
127
- ) subquery_for_count);
128
- should_lock := running_count < OLD.max_concurrent;
129
- END IF;
130
-
131
- IF should_lock THEN
132
- PERFORM pg_advisory_xact_lock(half_md5_as_bigint(OLD.strand));
133
- END IF;
134
-
135
- IF should_be_precise THEN
136
- running_count := (SELECT COUNT(*) FROM (
137
- SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
138
- ) subquery_for_count);
139
- IF running_count < OLD.max_concurrent THEN
140
- UPDATE delayed_jobs SET next_in_strand = 't' WHERE id IN (
141
- SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
142
- j2.strand = OLD.strand ORDER BY j2.strand_order_override ASC, j2.id ASC LIMIT (OLD.max_concurrent - running_count) FOR UPDATE
143
- );
144
- END IF;
145
- ELSE
146
- -- n-strands don't require precise ordering; we can make this query more performant
147
- IF OLD.max_concurrent > 1 THEN
148
- UPDATE delayed_jobs SET next_in_strand = 't' WHERE id =
149
- (SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
150
- j2.strand = OLD.strand ORDER BY j2.strand_order_override ASC, j2.id ASC LIMIT 1 FOR UPDATE SKIP LOCKED);
151
- ELSE
152
- UPDATE delayed_jobs SET next_in_strand = 't' WHERE id =
153
- (SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
154
- j2.strand = OLD.strand ORDER BY j2.strand_order_override ASC, j2.id ASC LIMIT 1 FOR UPDATE);
155
- END IF;
156
- END IF;
157
- END IF;
158
- RETURN OLD;
159
- END;
160
- $$ LANGUAGE plpgsql SET search_path TO #{::Switchman::Shard.current.name};
161
- SQL
162
- execute(<<~SQL)
163
- CREATE OR REPLACE FUNCTION #{connection.quote_table_name('delayed_jobs_before_insert_row_tr_fn')} () RETURNS trigger AS $$
164
- BEGIN
165
- IF NEW.strand IS NOT NULL THEN
166
- PERFORM pg_advisory_xact_lock(half_md5_as_bigint(NEW.strand));
167
- IF (SELECT COUNT(*) FROM (
168
- SELECT 1 AS one FROM delayed_jobs WHERE strand = NEW.strand LIMIT NEW.max_concurrent
169
- ) subquery_for_count) = NEW.max_concurrent THEN
170
- NEW.next_in_strand := 'f';
171
- END IF;
172
- END IF;
173
- RETURN NEW;
174
- END;
175
- $$ LANGUAGE plpgsql SET search_path TO #{::Switchman::Shard.current.name};
176
- SQL
177
- end
178
- end
179
-
180
- connection.transaction do
181
- reversible do |direction|
182
- direction.up do
183
- drop_triggers
184
- execute("CREATE TRIGGER delayed_jobs_before_insert_row_tr BEFORE INSERT ON #{::Delayed::Job.quoted_table_name} FOR EACH ROW WHEN (NEW.strand IS NOT NULL OR NEW.singleton IS NOT NULL) EXECUTE PROCEDURE #{connection.quote_table_name('delayed_jobs_before_insert_row_tr_fn')}()")
185
- execute("CREATE TRIGGER delayed_jobs_after_delete_row_tr AFTER DELETE ON #{::Delayed::Job.quoted_table_name} FOR EACH ROW WHEN ((OLD.strand IS NOT NULL OR OLD.singleton IS NOT NULL) AND OLD.next_in_strand=true) EXECUTE PROCEDURE #{connection.quote_table_name('delayed_jobs_after_delete_row_tr_fn')}()")
186
- end
187
- direction.down do
188
- drop_triggers
189
- execute("CREATE TRIGGER delayed_jobs_before_insert_row_tr BEFORE INSERT ON #{::Delayed::Job.quoted_table_name} FOR EACH ROW WHEN (NEW.strand IS NOT NULL) EXECUTE PROCEDURE #{connection.quote_table_name('delayed_jobs_before_insert_row_tr_fn')}()")
190
- execute("CREATE TRIGGER delayed_jobs_after_delete_row_tr AFTER DELETE ON #{::Delayed::Job.quoted_table_name} FOR EACH ROW WHEN (OLD.strand IS NOT NULL AND OLD.next_in_strand = 't') EXECUTE PROCEDURE #{connection.quote_table_name('delayed_jobs_after_delete_row_tr_fn()')}")
191
- end
192
- end
193
- end
194
- end
195
-
196
- def drop_triggers
197
- execute("DROP TRIGGER delayed_jobs_before_insert_row_tr ON #{::Delayed::Job.quoted_table_name}")
198
- execute("DROP TRIGGER delayed_jobs_after_delete_row_tr ON #{::Delayed::Job.quoted_table_name}")
199
- end
200
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class AddDeleteConflictingSingletonsBeforeUnlockTrigger < ActiveRecord::Migration[5.2]
4
- def up
5
- execute(<<~SQL)
6
- CREATE FUNCTION #{connection.quote_table_name('delayed_jobs_before_unlock_delete_conflicting_singletons_row_fn')} () RETURNS trigger AS $$
7
- BEGIN
8
- IF EXISTS (SELECT 1 FROM delayed_jobs j2 WHERE j2.singleton=OLD.singleton) THEN
9
- DELETE FROM delayed_jobs WHERE id<>OLD.id AND singleton=OLD.singleton;
10
- END IF;
11
- RETURN NEW;
12
- END;
13
- $$ LANGUAGE plpgsql SET search_path TO #{::Switchman::Shard.current.name};
14
- SQL
15
- execute(<<~SQL)
16
- CREATE TRIGGER delayed_jobs_before_unlock_delete_conflicting_singletons_row_tr BEFORE UPDATE ON #{::Delayed::Job.quoted_table_name} FOR EACH ROW WHEN (
17
- OLD.singleton IS NOT NULL AND
18
- OLD.singleton=NEW.singleton AND
19
- OLD.locked_by IS NOT NULL AND
20
- NEW.locked_by IS NULL) EXECUTE PROCEDURE #{connection.quote_table_name('delayed_jobs_before_unlock_delete_conflicting_singletons_row_fn')}();
21
- SQL
22
- end
23
-
24
- def down
25
- execute("DROP FUNCTION #{connection.quote_table_name('delayed_jobs_before_unlock_delete_conflicting_singletons_row_tr_fn')}() CASCADE")
26
- end
27
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class FixSingletonConditionInBeforeInsert < ActiveRecord::Migration[5.2]
4
- def change
5
- reversible do |direction|
6
- direction.up do
7
- execute(<<~SQL)
8
- CREATE OR REPLACE FUNCTION #{connection.quote_table_name('delayed_jobs_before_insert_row_tr_fn')} () RETURNS trigger AS $$
9
- BEGIN
10
- IF NEW.strand IS NOT NULL THEN
11
- PERFORM pg_advisory_xact_lock(half_md5_as_bigint(NEW.strand));
12
- IF (SELECT COUNT(*) FROM (
13
- SELECT 1 FROM delayed_jobs WHERE strand = NEW.strand AND next_in_strand=true LIMIT NEW.max_concurrent
14
- ) s) = NEW.max_concurrent THEN
15
- NEW.next_in_strand := false;
16
- END IF;
17
- END IF;
18
- IF NEW.singleton IS NOT NULL THEN
19
- -- this condition seems silly, but it forces postgres to use the two partial indexes on singleton,
20
- -- rather than doing a seq scan
21
- PERFORM 1 FROM delayed_jobs WHERE singleton = NEW.singleton AND (locked_by IS NULL OR locked_by IS NOT NULL);
22
- IF FOUND THEN
23
- NEW.next_in_strand := false;
24
- END IF;
25
- END IF;
26
- RETURN NEW;
27
- END;
28
- $$ LANGUAGE plpgsql SET search_path TO #{::Switchman::Shard.current.name};
29
- SQL
30
- end
31
- direction.down do
32
- execute(<<~SQL)
33
- CREATE OR REPLACE FUNCTION #{connection.quote_table_name('delayed_jobs_before_insert_row_tr_fn')} () RETURNS trigger AS $$
34
- BEGIN
35
- IF NEW.strand IS NOT NULL THEN
36
- PERFORM pg_advisory_xact_lock(half_md5_as_bigint(NEW.strand));
37
- IF (SELECT COUNT(*) FROM (
38
- SELECT 1 FROM delayed_jobs WHERE strand = NEW.strand AND next_in_strand=true LIMIT NEW.max_concurrent
39
- ) s) = NEW.max_concurrent THEN
40
- NEW.next_in_strand := false;
41
- END IF;
42
- END IF;
43
- IF NEW.singleton IS NOT NULL THEN
44
- PERFORM 1 FROM delayed_jobs WHERE singleton = NEW.singleton;
45
- IF FOUND THEN
46
- NEW.next_in_strand := false;
47
- END IF;
48
- END IF;
49
- RETURN NEW;
50
- END;
51
- $$ LANGUAGE plpgsql SET search_path TO #{::Switchman::Shard.current.name};
52
- SQL
53
- end
54
- end
55
- end
56
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class UpdateConflictingSingletonFunctionToUseIndex < ActiveRecord::Migration[5.2]
4
- def up
5
- execute(<<~SQL)
6
- CREATE OR REPLACE FUNCTION #{connection.quote_table_name('delayed_jobs_before_unlock_delete_conflicting_singletons_row_fn')} () RETURNS trigger AS $$
7
- BEGIN
8
- DELETE FROM delayed_jobs WHERE id<>OLD.id AND singleton=OLD.singleton AND locked_by IS NULL;
9
- RETURN NEW;
10
- END;
11
- $$ LANGUAGE plpgsql SET search_path TO #{::Switchman::Shard.current.name};
12
- SQL
13
- end
14
-
15
- def down
16
- execute(<<~SQL)
17
- CREATE OR REPLACE FUNCTION #{connection.quote_table_name('delayed_jobs_before_unlock_delete_conflicting_singletons_row_fn')} () RETURNS trigger AS $$
18
- BEGIN
19
- IF EXISTS (SELECT 1 FROM delayed_jobs j2 WHERE j2.singleton=OLD.singleton) THEN
20
- DELETE FROM delayed_jobs WHERE id<>OLD.id AND singleton=OLD.singleton;
21
- END IF;
22
- RETURN NEW;
23
- END;
24
- $$ LANGUAGE plpgsql SET search_path TO #{::Switchman::Shard.current.name};
25
- SQL
26
- end
27
- end