queue_classic_plus 4.0.0.alpha15 → 4.0.0.alpha17

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: 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