inst-jobs 0.15.21 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/db/migrate/20101216224513_create_delayed_jobs.rb +2 -0
- data/db/migrate/20110208031356_add_delayed_jobs_tag.rb +2 -0
- data/db/migrate/20110426161613_add_delayed_jobs_max_attempts.rb +2 -0
- data/db/migrate/20110516225834_add_delayed_jobs_strand.rb +2 -0
- data/db/migrate/20110531144916_cleanup_delayed_jobs_indexes.rb +2 -0
- data/db/migrate/20110610213249_optimize_delayed_jobs.rb +2 -0
- data/db/migrate/20110831210257_add_delayed_jobs_next_in_strand.rb +2 -0
- data/db/migrate/20120510004759_delayed_jobs_delete_trigger_lock_for_update.rb +2 -0
- data/db/migrate/20120531150712_drop_psql_jobs_pop_fn.rb +2 -0
- data/db/migrate/20120607164022_delayed_jobs_use_advisory_locks.rb +2 -0
- data/db/migrate/20120607181141_index_jobs_on_locked_by.rb +2 -0
- data/db/migrate/20120608191051_add_jobs_run_at_index.rb +2 -0
- data/db/migrate/20120927184213_change_delayed_jobs_handler_to_text.rb +2 -0
- data/db/migrate/20140505215131_add_failed_jobs_original_job_id.rb +2 -0
- data/db/migrate/20140505215510_copy_failed_jobs_original_id.rb +2 -0
- data/db/migrate/20140505223637_drop_failed_jobs_original_id.rb +2 -0
- data/db/migrate/20140512213941_add_source_to_jobs.rb +2 -0
- data/db/migrate/20150807133223_add_max_concurrent_to_jobs.rb +2 -0
- data/db/migrate/20151123210429_add_expires_at_to_jobs.rb +2 -0
- data/db/migrate/20151210162949_improve_max_concurrent.rb +2 -0
- data/db/migrate/20161206323555_add_back_default_string_limits_jobs.rb +2 -0
- data/db/migrate/20181217155351_speed_up_max_concurrent_triggers.rb +2 -0
- data/db/migrate/20190726154743_make_critical_columns_not_null.rb +2 -0
- data/db/migrate/20200330230722_add_id_to_get_delayed_jobs_index.rb +2 -0
- data/db/migrate/20200824222232_speed_up_max_concurrent_delete_trigger.rb +97 -0
- data/db/migrate/20200825011002_add_strand_order_override.rb +128 -0
- data/lib/delayed/backend/active_record.rb +9 -5
- data/lib/delayed/backend/base.rb +34 -20
- data/lib/delayed/backend/redis/functions.rb +2 -0
- data/lib/delayed/backend/redis/job.rb +2 -0
- data/lib/delayed/batch.rb +5 -3
- data/lib/delayed/cli.rb +2 -0
- data/lib/delayed/core_ext/kernel.rb +9 -0
- data/lib/delayed/daemon.rb +2 -0
- data/lib/delayed/engine.rb +2 -0
- data/lib/delayed/job_tracking.rb +2 -0
- data/lib/delayed/lifecycle.rb +2 -0
- data/lib/delayed/log_tailer.rb +2 -0
- data/lib/delayed/logging.rb +2 -0
- data/lib/delayed/message_sending.rb +90 -106
- data/lib/delayed/performable_method.rb +34 -6
- data/lib/delayed/periodic.rb +6 -4
- data/lib/delayed/plugin.rb +2 -0
- data/lib/delayed/pool.rb +2 -0
- data/lib/delayed/server.rb +2 -0
- data/lib/delayed/server/helpers.rb +2 -0
- data/lib/delayed/settings.rb +7 -1
- data/lib/delayed/testing.rb +2 -0
- data/lib/delayed/version.rb +3 -1
- data/lib/delayed/work_queue/in_process.rb +2 -0
- data/lib/delayed/work_queue/parent_process.rb +2 -0
- data/lib/delayed/work_queue/parent_process/client.rb +2 -0
- data/lib/delayed/work_queue/parent_process/server.rb +2 -0
- data/lib/delayed/worker.rb +3 -1
- data/lib/delayed/worker/consul_health_check.rb +3 -1
- data/lib/delayed/worker/health_check.rb +2 -0
- data/lib/delayed/worker/null_health_check.rb +2 -0
- data/lib/delayed/worker/process_helper.rb +2 -0
- data/lib/delayed/yaml_extensions.rb +2 -0
- data/lib/delayed_job.rb +4 -0
- data/lib/inst-jobs.rb +2 -0
- data/spec/active_record_job_spec.rb +4 -6
- data/spec/delayed/cli_spec.rb +2 -0
- data/spec/delayed/daemon_spec.rb +2 -0
- data/spec/delayed/message_sending_spec.rb +101 -0
- data/spec/delayed/server_spec.rb +2 -4
- data/spec/delayed/settings_spec.rb +2 -0
- data/spec/delayed/work_queue/in_process_spec.rb +2 -4
- data/spec/delayed/work_queue/parent_process/client_spec.rb +2 -4
- data/spec/delayed/work_queue/parent_process/server_spec.rb +2 -1
- data/spec/delayed/work_queue/parent_process_spec.rb +2 -1
- data/spec/delayed/worker/consul_health_check_spec.rb +3 -1
- data/spec/delayed/worker/health_check_spec.rb +2 -0
- data/spec/delayed/worker_spec.rb +29 -0
- data/spec/gemfiles/42.gemfile.lock +192 -0
- data/spec/gemfiles/50.gemfile.lock +197 -0
- data/spec/gemfiles/51.gemfile.lock +198 -0
- data/spec/gemfiles/52.gemfile.lock +206 -0
- data/spec/gemfiles/60.gemfile.lock +224 -0
- data/spec/migrate/20140924140513_add_story_table.rb +2 -0
- data/spec/redis_job_spec.rb +10 -12
- data/spec/sample_jobs.rb +2 -0
- data/spec/shared/delayed_batch.rb +17 -15
- data/spec/shared/delayed_method.rb +49 -204
- data/spec/shared/performable_method.rb +11 -9
- data/spec/shared/shared_backend.rb +27 -25
- data/spec/shared/testing.rb +7 -5
- data/spec/shared/worker.rb +15 -13
- data/spec/shared_jobs_specs.rb +2 -0
- data/spec/spec_helper.rb +12 -1
- metadata +36 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6d65c567b52e2baf26955d266c9fededc001deab65d871e6e60a42a905d552e8
|
|
4
|
+
data.tar.gz: b4d487088aba583188c90650a42a20726f84230e346c321b4b94ddc5c25fe36e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9ade674610c5a1a4a04e4a6078b45c38358e7c7af79a417d5e6941d968e1565bc5e217405ad1ca427b373ee0d89bdbc28772f8ed52047394e8760fc09a79b60a
|
|
7
|
+
data.tar.gz: 216706e128397e84ba87d495e4b09d30eb58f35ab4821e8ef6f484d5f6226a959cab04a8bfdfa22916f19dad53e7ee01bbe1128bd61fb402aad29885ac81839f
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class SpeedUpMaxConcurrentDeleteTrigger < ActiveRecord::Migration[4.2]
|
|
4
|
+
def connection
|
|
5
|
+
Delayed::Job.connection
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def up
|
|
9
|
+
if connection.adapter_name == 'PostgreSQL'
|
|
10
|
+
# tl;dr sacrifice some responsiveness to max_concurrent changes for faster performance
|
|
11
|
+
# don't get the count every single time - it's usually safe to just set the next one in line
|
|
12
|
+
# since the max_concurrent doesn't change all that often for a strand
|
|
13
|
+
execute(<<-SQL)
|
|
14
|
+
CREATE OR REPLACE FUNCTION delayed_jobs_after_delete_row_tr_fn () RETURNS trigger AS $$
|
|
15
|
+
DECLARE
|
|
16
|
+
running_count integer;
|
|
17
|
+
should_lock boolean;
|
|
18
|
+
should_be_precise boolean;
|
|
19
|
+
BEGIN
|
|
20
|
+
IF OLD.strand IS NOT NULL THEN
|
|
21
|
+
should_lock := true;
|
|
22
|
+
should_be_precise := OLD.id % (OLD.max_concurrent * 4) = 0;
|
|
23
|
+
|
|
24
|
+
IF NOT should_be_precise AND OLD.max_concurrent > 16 THEN
|
|
25
|
+
running_count := (SELECT COUNT(*) FROM (
|
|
26
|
+
SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
|
|
27
|
+
) subquery_for_count);
|
|
28
|
+
should_lock := running_count < OLD.max_concurrent;
|
|
29
|
+
END IF;
|
|
30
|
+
|
|
31
|
+
IF should_lock THEN
|
|
32
|
+
PERFORM pg_advisory_xact_lock(half_md5_as_bigint(OLD.strand));
|
|
33
|
+
END IF;
|
|
34
|
+
|
|
35
|
+
IF should_be_precise THEN
|
|
36
|
+
running_count := (SELECT COUNT(*) FROM (
|
|
37
|
+
SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
|
|
38
|
+
) subquery_for_count);
|
|
39
|
+
IF running_count < OLD.max_concurrent THEN
|
|
40
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id IN (
|
|
41
|
+
SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
42
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT (OLD.max_concurrent - running_count) FOR UPDATE
|
|
43
|
+
);
|
|
44
|
+
END IF;
|
|
45
|
+
ELSE
|
|
46
|
+
-- n-strands don't require precise ordering; we can make this query more performant
|
|
47
|
+
IF OLD.max_concurrent > 1 THEN
|
|
48
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id =
|
|
49
|
+
(SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
50
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT 1 FOR UPDATE SKIP LOCKED);
|
|
51
|
+
ELSE
|
|
52
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id =
|
|
53
|
+
(SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
54
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT 1 FOR UPDATE);
|
|
55
|
+
END IF;
|
|
56
|
+
END IF;
|
|
57
|
+
END IF;
|
|
58
|
+
RETURN OLD;
|
|
59
|
+
END;
|
|
60
|
+
$$ LANGUAGE plpgsql;
|
|
61
|
+
SQL
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def down
|
|
66
|
+
if connection.adapter_name == 'PostgreSQL'
|
|
67
|
+
execute(<<-SQL)
|
|
68
|
+
CREATE OR REPLACE FUNCTION delayed_jobs_after_delete_row_tr_fn () RETURNS trigger AS $$
|
|
69
|
+
DECLARE
|
|
70
|
+
running_count integer;
|
|
71
|
+
BEGIN
|
|
72
|
+
IF OLD.strand IS NOT NULL THEN
|
|
73
|
+
PERFORM pg_advisory_xact_lock(half_md5_as_bigint(OLD.strand));
|
|
74
|
+
IF OLD.id % 20 = 0 THEN
|
|
75
|
+
running_count := (SELECT COUNT(*) FROM (
|
|
76
|
+
SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
|
|
77
|
+
) subquery_for_count);
|
|
78
|
+
IF running_count < OLD.max_concurrent THEN
|
|
79
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id IN (
|
|
80
|
+
SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
81
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT (OLD.max_concurrent - running_count) FOR UPDATE
|
|
82
|
+
);
|
|
83
|
+
END IF;
|
|
84
|
+
ELSE
|
|
85
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id =
|
|
86
|
+
(SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
87
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT 1 FOR UPDATE);
|
|
88
|
+
END IF;
|
|
89
|
+
END IF;
|
|
90
|
+
RETURN OLD;
|
|
91
|
+
END;
|
|
92
|
+
$$ LANGUAGE plpgsql;
|
|
93
|
+
SQL
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddStrandOrderOverride < ActiveRecord::Migration[4.2]
|
|
4
|
+
disable_ddl_transaction! if respond_to?(:disable_ddl_transaction!)
|
|
5
|
+
|
|
6
|
+
def connection
|
|
7
|
+
Delayed::Job.connection
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def up
|
|
11
|
+
add_column :delayed_jobs, :strand_order_override, :integer, default: 0, null: false
|
|
12
|
+
add_column :failed_jobs, :strand_order_override, :integer, default: 0, null: false
|
|
13
|
+
add_index :delayed_jobs, [:strand, :strand_order_override, :id],
|
|
14
|
+
algorithm: :concurrently,
|
|
15
|
+
where: "strand IS NOT NULL",
|
|
16
|
+
name: "next_in_strand_index"
|
|
17
|
+
|
|
18
|
+
if connection.adapter_name == 'PostgreSQL'
|
|
19
|
+
# Use the strand_order_override as the primary sorting mechanism (useful when moving between jobs queues without preserving ID ordering)
|
|
20
|
+
execute(<<-SQL)
|
|
21
|
+
CREATE OR REPLACE FUNCTION delayed_jobs_after_delete_row_tr_fn () RETURNS trigger AS $$
|
|
22
|
+
DECLARE
|
|
23
|
+
running_count integer;
|
|
24
|
+
should_lock boolean;
|
|
25
|
+
should_be_precise boolean;
|
|
26
|
+
BEGIN
|
|
27
|
+
IF OLD.strand IS NOT NULL THEN
|
|
28
|
+
should_lock := true;
|
|
29
|
+
should_be_precise := OLD.id % (OLD.max_concurrent * 4) = 0;
|
|
30
|
+
|
|
31
|
+
IF NOT should_be_precise AND OLD.max_concurrent > 16 THEN
|
|
32
|
+
running_count := (SELECT COUNT(*) FROM (
|
|
33
|
+
SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
|
|
34
|
+
) subquery_for_count);
|
|
35
|
+
should_lock := running_count < OLD.max_concurrent;
|
|
36
|
+
END IF;
|
|
37
|
+
|
|
38
|
+
IF should_lock THEN
|
|
39
|
+
PERFORM pg_advisory_xact_lock(half_md5_as_bigint(OLD.strand));
|
|
40
|
+
END IF;
|
|
41
|
+
|
|
42
|
+
IF should_be_precise THEN
|
|
43
|
+
running_count := (SELECT COUNT(*) FROM (
|
|
44
|
+
SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
|
|
45
|
+
) subquery_for_count);
|
|
46
|
+
IF running_count < OLD.max_concurrent THEN
|
|
47
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id IN (
|
|
48
|
+
SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
49
|
+
j2.strand = OLD.strand ORDER BY j2.strand_order_override ASC, j2.id ASC LIMIT (OLD.max_concurrent - running_count) FOR UPDATE
|
|
50
|
+
);
|
|
51
|
+
END IF;
|
|
52
|
+
ELSE
|
|
53
|
+
-- n-strands don't require precise ordering; we can make this query more performant
|
|
54
|
+
IF OLD.max_concurrent > 1 THEN
|
|
55
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id =
|
|
56
|
+
(SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
57
|
+
j2.strand = OLD.strand ORDER BY j2.strand_order_override ASC, j2.id ASC LIMIT 1 FOR UPDATE SKIP LOCKED);
|
|
58
|
+
ELSE
|
|
59
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id =
|
|
60
|
+
(SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
61
|
+
j2.strand = OLD.strand ORDER BY j2.strand_order_override ASC, j2.id ASC LIMIT 1 FOR UPDATE);
|
|
62
|
+
END IF;
|
|
63
|
+
END IF;
|
|
64
|
+
END IF;
|
|
65
|
+
RETURN OLD;
|
|
66
|
+
END;
|
|
67
|
+
$$ LANGUAGE plpgsql;
|
|
68
|
+
SQL
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def down
|
|
73
|
+
remove_column :delayed_jobs, :strand_order_override, :integer
|
|
74
|
+
remove_column :failed_jobs, :strand_order_override, :integer
|
|
75
|
+
|
|
76
|
+
if connection.adapter_name == 'PostgreSQL'
|
|
77
|
+
execute(<<-SQL)
|
|
78
|
+
CREATE OR REPLACE FUNCTION delayed_jobs_after_delete_row_tr_fn () RETURNS trigger AS $$
|
|
79
|
+
DECLARE
|
|
80
|
+
running_count integer;
|
|
81
|
+
should_lock boolean;
|
|
82
|
+
should_be_precise boolean;
|
|
83
|
+
BEGIN
|
|
84
|
+
IF OLD.strand IS NOT NULL THEN
|
|
85
|
+
should_lock := true;
|
|
86
|
+
should_be_precise := OLD.id % (OLD.max_concurrent * 4) = 0;
|
|
87
|
+
|
|
88
|
+
IF NOT should_be_precise AND OLD.max_concurrent > 16 THEN
|
|
89
|
+
running_count := (SELECT COUNT(*) FROM (
|
|
90
|
+
SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
|
|
91
|
+
) subquery_for_count);
|
|
92
|
+
should_lock := running_count < OLD.max_concurrent;
|
|
93
|
+
END IF;
|
|
94
|
+
|
|
95
|
+
IF should_lock THEN
|
|
96
|
+
PERFORM pg_advisory_xact_lock(half_md5_as_bigint(OLD.strand));
|
|
97
|
+
END IF;
|
|
98
|
+
|
|
99
|
+
IF should_be_precise THEN
|
|
100
|
+
running_count := (SELECT COUNT(*) FROM (
|
|
101
|
+
SELECT 1 as one FROM delayed_jobs WHERE strand = OLD.strand AND next_in_strand = 't' LIMIT OLD.max_concurrent
|
|
102
|
+
) subquery_for_count);
|
|
103
|
+
IF running_count < OLD.max_concurrent THEN
|
|
104
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id IN (
|
|
105
|
+
SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
106
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT (OLD.max_concurrent - running_count) FOR UPDATE
|
|
107
|
+
);
|
|
108
|
+
END IF;
|
|
109
|
+
ELSE
|
|
110
|
+
-- n-strands don't require precise ordering; we can make this query more performant
|
|
111
|
+
IF OLD.max_concurrent > 1 THEN
|
|
112
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id =
|
|
113
|
+
(SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
114
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT 1 FOR UPDATE SKIP LOCKED);
|
|
115
|
+
ELSE
|
|
116
|
+
UPDATE delayed_jobs SET next_in_strand = 't' WHERE id =
|
|
117
|
+
(SELECT id FROM delayed_jobs j2 WHERE next_in_strand = 'f' AND
|
|
118
|
+
j2.strand = OLD.strand ORDER BY j2.id ASC LIMIT 1 FOR UPDATE);
|
|
119
|
+
END IF;
|
|
120
|
+
END IF;
|
|
121
|
+
END IF;
|
|
122
|
+
RETURN OLD;
|
|
123
|
+
END;
|
|
124
|
+
$$ LANGUAGE plpgsql;
|
|
125
|
+
SQL
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class ActiveRecord::Base
|
|
2
4
|
def self.load_for_delayed_job(id)
|
|
3
5
|
if id
|
|
@@ -17,6 +19,8 @@ module Delayed
|
|
|
17
19
|
include Delayed::Backend::Base
|
|
18
20
|
self.table_name = :delayed_jobs
|
|
19
21
|
|
|
22
|
+
scope :next_in_strand_order, -> { order(:strand_order_override, :id) }
|
|
23
|
+
|
|
20
24
|
def self.reconnect!
|
|
21
25
|
clear_all_connections!
|
|
22
26
|
end
|
|
@@ -103,7 +107,7 @@ module Delayed
|
|
|
103
107
|
# so rather than changing the strand and balancing at queue time,
|
|
104
108
|
# this keeps the strand intact and uses triggers to limit the number running
|
|
105
109
|
def self.n_strand_options(strand_name, num_strands)
|
|
106
|
-
{:
|
|
110
|
+
{ strand: strand_name, max_concurrent: num_strands }
|
|
107
111
|
end
|
|
108
112
|
|
|
109
113
|
def self.current
|
|
@@ -123,8 +127,8 @@ module Delayed
|
|
|
123
127
|
end
|
|
124
128
|
|
|
125
129
|
# a nice stress test:
|
|
126
|
-
# 10_000.times { |i| Kernel.
|
|
127
|
-
# 500.times { |i| "ohai".
|
|
130
|
+
# 10_000.times { |i| Kernel.delay(strand: 's1', run_at: (24.hours.ago + (rand(24.hours.to_i))).system("echo #{i} >> test1.txt") }
|
|
131
|
+
# 500.times { |i| "ohai".delay(run_at: (12.hours.ago + (rand(24.hours.to_i))).reverse }
|
|
128
132
|
# then fire up your workers
|
|
129
133
|
# you can check out strand correctness: diff test1.txt <(sort -n test1.txt)
|
|
130
134
|
def self.ready_to_run(forced_latency: nil)
|
|
@@ -286,7 +290,7 @@ module Delayed
|
|
|
286
290
|
lock(lock)
|
|
287
291
|
jobs_with_row_number = all.from(target_jobs).
|
|
288
292
|
select("id, ROW_NUMBER() OVER () AS row_number")
|
|
289
|
-
updates = "locked_by = CASE row_number "
|
|
293
|
+
updates = +"locked_by = CASE row_number "
|
|
290
294
|
effective_worker_names.each_with_index do |worker, i|
|
|
291
295
|
updates << "WHEN #{i + 1} THEN #{connection.quote(worker)} "
|
|
292
296
|
end
|
|
@@ -398,7 +402,7 @@ module Delayed
|
|
|
398
402
|
strand = options[:strand]
|
|
399
403
|
on_conflict = options.delete(:on_conflict) || :use_earliest
|
|
400
404
|
transaction_for_singleton(strand, on_conflict) do
|
|
401
|
-
job = self.where(:strand => strand, :locked_at => nil).
|
|
405
|
+
job = self.where(:strand => strand, :locked_at => nil).next_in_strand_order.first
|
|
402
406
|
new_job = new(options)
|
|
403
407
|
if job
|
|
404
408
|
new_job.initialize_defaults
|