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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 634ceaedff254e0c5382a484d574d6971101362a88b9d2185303d95298de06c8
4
- data.tar.gz: '03509124366e931f02d928226da3b05ec3e625c5888eaba88f5669ee090566b6'
3
+ metadata.gz: 3b17bbec023aa5f8fa91527f15c91db3ca6a9975da20c304188b5100757bab9b
4
+ data.tar.gz: 57ce60a1dfd1912b7a6b57c6b8c312f78fc3f903dc674739099dc27bb138d8aa
5
5
  SHA512:
6
- metadata.gz: 4c8b6ff9e377c59b579c7309ee1f75e3fb583b00450ef09548f46d5d6e921c2553cf64037b259a1267b2781276f2e06ccceb3c8e5d6bc76373dc9e64e7a61522
7
- data.tar.gz: d3852486ebdf22d4c59d142a8f00257f2fa7b0847d09704001644e56cb5ab91845ba154807bc2699491f379b62c98656da7b70735c9b3d3ba13638efaddfefb6
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
- conn = QC.default_conn_adapter.connection
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
@@ -1,3 +1,3 @@
1
1
  module QueueClassicPlus
2
- VERSION = '4.0.0.alpha15'.freeze
2
+ VERSION = '4.0.0.alpha17'.freeze
3
3
  end
@@ -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
- 50.times do
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.alpha15
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-09 00:00:00.000000000 Z
13
+ date: 2023-08-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: queue_classic