queue_classic_plus 4.0.0.alpha15 → 4.0.0.alpha17
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/lib/queue_classic_plus/base.rb +1 -39
- data/lib/queue_classic_plus/queue_classic/queue.rb +20 -0
- data/lib/queue_classic_plus/version.rb +1 -1
- data/lib/queue_classic_plus.rb +8 -4
- data/spec/base_spec.rb +32 -9
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b17bbec023aa5f8fa91527f15c91db3ca6a9975da20c304188b5100757bab9b
|
4
|
+
data.tar.gz: 57ce60a1dfd1912b7a6b57c6b8c312f78fc3f903dc674739099dc27bb138d8aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e45d48b488c7cc0bdea10fbea03397539a5533b1d98647aaf9f942150caaa121dc958bc57cc183782ffc7b74c98305a90ef14c9d07dfcb00b562372bf0c7048b
|
7
|
+
data.tar.gz: 23932d46b74e4f994b4e8a09d6b81e933f0798fa45608968e63f37b39476de0428c6315ebb925e18b043dabc4b10d0d8336e72d65407f61ba5e678c591d9918a
|
@@ -6,10 +6,6 @@ module QueueClassicPlus
|
|
6
6
|
QC::Queue.new(@queue)
|
7
7
|
end
|
8
8
|
|
9
|
-
def self.queue_name_digest
|
10
|
-
@queue_name_digest ||= @queue.to_s.to_i(36)
|
11
|
-
end
|
12
|
-
|
13
9
|
inheritable_attr :locked
|
14
10
|
inheritable_attr :skip_transaction
|
15
11
|
inheritable_attr :retries_on
|
@@ -56,42 +52,8 @@ module QueueClassicPlus
|
|
56
52
|
QueueClassicPlus.logger
|
57
53
|
end
|
58
54
|
|
59
|
-
def self.can_enqueue?(method, *args)
|
60
|
-
if locked?
|
61
|
-
max_lock_time = ENV.fetch("QUEUE_CLASSIC_MAX_LOCK_TIME", 10 * 60).to_i
|
62
|
-
|
63
|
-
q = "SELECT COUNT(1) AS count
|
64
|
-
FROM
|
65
|
-
(
|
66
|
-
SELECT 1
|
67
|
-
FROM queue_classic_jobs
|
68
|
-
WHERE q_name = $1 AND method = $2 AND args::text = $3::text
|
69
|
-
AND (locked_at IS NULL OR locked_at > current_timestamp - interval '#{max_lock_time} seconds')
|
70
|
-
LIMIT 1
|
71
|
-
)
|
72
|
-
AS x"
|
73
|
-
|
74
|
-
result = QC.default_conn_adapter.execute(q, @queue, method, JSON.dump(serialized(args)))
|
75
|
-
result['count'].to_i == 0
|
76
|
-
else
|
77
|
-
true
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
55
|
def self.enqueue(method, *args)
|
82
|
-
|
83
|
-
check_and_enqueue = proc do
|
84
|
-
conn.exec("SELECT pg_advisory_xact_lock(#{queue_name_digest})")
|
85
|
-
if can_enqueue?(method, *args)
|
86
|
-
queue.enqueue(method, *serialized(args))
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
if [PG::PQTRANS_ACTIVE, PG::PQTRANS_INTRANS].include?(conn.transaction_status)
|
91
|
-
check_and_enqueue.call
|
92
|
-
else
|
93
|
-
conn.transaction &check_and_enqueue
|
94
|
-
end
|
56
|
+
queue.enqueue(method, *serialized(args), lock: locked?)
|
95
57
|
end
|
96
58
|
|
97
59
|
def self.enqueue_perform(*args)
|
@@ -50,5 +50,25 @@ module QC
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
+
def enqueue(method, *args, lock: false)
|
54
|
+
QC.log_yield(:measure => 'queue.enqueue') do
|
55
|
+
insert_sql = <<-EOF
|
56
|
+
INSERT INTO #{QC.table_name} (q_name, method, args, lock)
|
57
|
+
VALUES ($1, $2, $3, $4)
|
58
|
+
ON CONFLICT (q_name, method, args) WHERE lock IS TRUE DO NOTHING
|
59
|
+
RETURNING id
|
60
|
+
EOF
|
61
|
+
begin
|
62
|
+
retries ||= 0
|
63
|
+
conn_adapter.execute(insert_sql, name, method, JSON.dump(args), lock)
|
64
|
+
rescue PG::Error => error
|
65
|
+
if (retries += 1) < 2
|
66
|
+
retry
|
67
|
+
else
|
68
|
+
raise
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
53
73
|
end
|
54
74
|
end
|
data/lib/queue_classic_plus.rb
CHANGED
@@ -15,14 +15,18 @@ module QueueClassicPlus
|
|
15
15
|
|
16
16
|
def self.migrate(c = QC::default_conn_adapter.connection)
|
17
17
|
conn = QC::ConnAdapter.new(connection: c)
|
18
|
-
conn.execute("ALTER TABLE queue_classic_jobs ADD COLUMN last_error TEXT")
|
19
|
-
conn.execute("ALTER TABLE queue_classic_jobs ADD COLUMN remaining_retries INTEGER")
|
18
|
+
conn.execute("ALTER TABLE queue_classic_jobs ADD COLUMN IF NOT EXISTS last_error TEXT")
|
19
|
+
conn.execute("ALTER TABLE queue_classic_jobs ADD COLUMN IF NOT EXISTS remaining_retries INTEGER")
|
20
|
+
conn.execute("ALTER TABLE queue_classic_jobs ADD COLUMN IF NOT EXISTS lock BOOLEAN NOT NULL DEFAULT FALSE")
|
21
|
+
conn.execute("CREATE UNIQUE INDEX IF NOT EXISTS index_queue_classic_jobs_enqueue_lock on queue_classic_jobs(q_name, method, args) WHERE lock IS TRUE")
|
20
22
|
end
|
21
23
|
|
22
24
|
def self.demigrate(c = QC::default_conn_adapter.connection)
|
23
25
|
conn = QC::ConnAdapter.new(connection: c)
|
24
|
-
conn.execute("ALTER TABLE queue_classic_jobs DROP COLUMN last_error")
|
25
|
-
conn.execute("ALTER TABLE queue_classic_jobs DROP COLUMN remaining_retries")
|
26
|
+
conn.execute("ALTER TABLE queue_classic_jobs DROP COLUMN IF EXISTS last_error")
|
27
|
+
conn.execute("ALTER TABLE queue_classic_jobs DROP COLUMN IF EXISTS remaining_retries")
|
28
|
+
conn.execute("DROP INDEX IF EXISTS index_queue_classic_jobs_enqueue_lock")
|
29
|
+
conn.execute("ALTER TABLE queue_classic_jobs DROP COLUMN IF EXISTS lock")
|
26
30
|
end
|
27
31
|
|
28
32
|
def self.exception_handler
|
data/spec/base_spec.rb
CHANGED
@@ -3,6 +3,24 @@ require 'active_record'
|
|
3
3
|
|
4
4
|
describe QueueClassicPlus::Base do
|
5
5
|
context "A child of QueueClassicPlus::Base" do
|
6
|
+
subject do
|
7
|
+
Class.new(QueueClassicPlus::Base) do
|
8
|
+
@queue = :test
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "allows multiple enqueues" do
|
13
|
+
threads = []
|
14
|
+
10.times do
|
15
|
+
threads << Thread.new do
|
16
|
+
subject.do
|
17
|
+
end
|
18
|
+
end
|
19
|
+
threads.each(&:join)
|
20
|
+
|
21
|
+
expect(subject).to have_queue_size_of(10)
|
22
|
+
end
|
23
|
+
|
6
24
|
context "that is locked" do
|
7
25
|
subject do
|
8
26
|
Class.new(QueueClassicPlus::Base) do
|
@@ -13,14 +31,27 @@ describe QueueClassicPlus::Base do
|
|
13
31
|
|
14
32
|
it "does not allow multiple enqueues" do
|
15
33
|
threads = []
|
16
|
-
|
34
|
+
10.times do
|
17
35
|
threads << Thread.new do
|
18
36
|
subject.do
|
19
37
|
expect(subject).to have_queue_size_of(1)
|
20
38
|
end
|
21
39
|
end
|
40
|
+
threads.each(&:join)
|
41
|
+
end
|
22
42
|
|
43
|
+
it "allows enqueueing same job with different arguments" do
|
44
|
+
threads = []
|
45
|
+
(1..3).each do |arg|
|
46
|
+
10.times do
|
47
|
+
threads << Thread.new do
|
48
|
+
subject.do(arg)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
23
52
|
threads.each(&:join)
|
53
|
+
|
54
|
+
expect(subject).to have_queue_size_of(3)
|
24
55
|
end
|
25
56
|
|
26
57
|
it "checks for an existing job using the same serializing as job enqueuing" do
|
@@ -34,14 +65,6 @@ describe QueueClassicPlus::Base do
|
|
34
65
|
subject.do(date)
|
35
66
|
expect(subject).to have_queue_size_of(1)
|
36
67
|
end
|
37
|
-
|
38
|
-
it "does allow multiple enqueues if something got locked for too long" do
|
39
|
-
subject.do
|
40
|
-
one_day_ago = Time.now - 60*60*24
|
41
|
-
execute "UPDATE queue_classic_jobs SET locked_at = '#{one_day_ago}' WHERE q_name = 'test'"
|
42
|
-
subject.do
|
43
|
-
expect(subject).to have_queue_size_of(2)
|
44
|
-
end
|
45
68
|
end
|
46
69
|
|
47
70
|
context "when in a transaction" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: queue_classic_plus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.0.
|
4
|
+
version: 4.0.0.alpha17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon Mathieu
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-08-
|
13
|
+
date: 2023-08-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: queue_classic
|