delayed 2.0.0 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a42f2f7d06ec85c051b3a72e7e8644a750e703e6994cd89e75b151e098810fde
4
- data.tar.gz: 122a0e93f5790543eca0484c27f52eff1472f693d1c8eee5c0aef27e1cace575
3
+ metadata.gz: 16d1a1a8e3f41bee282a4d725afdf3be6419fceba8c5cef58a3eb35a7a406823
4
+ data.tar.gz: 9ad241b6880c13997ea7b58ba2bcfba02a1beb6692b050698fac30301cc9c90c
5
5
  SHA512:
6
- metadata.gz: 2238ccb8c25ef5e483faf3a6bfa43f1c72a2b81e2cd5312071d8dbc72ef96397e3b6dceaac61db962028524e9a6b06769005ce64e9a5a1b7b818a81a40554c95
7
- data.tar.gz: b255dee5f83ffe62155edaf65e552a3f6042656b60515b7721a0707ff78c2ed8f284d5e298b9448c2ee34cb8d574447619f9e78ec92da5f1dee461f4ebbe4b70
6
+ metadata.gz: a63a4f0a56f26c9b5bb3a987b6c2877068016823b21efb059744effc0eeb68255b4b193e7f0e0292f6d790e12138ad8c57bab032a7f1f3c1a89e2c533db45df6
7
+ data.tar.gz: 7912ee6d5d633293a2f1707d890c2fd5a60cbdb1c44ec215a8d2414db35902a272e4caad4ece1947c6475f4e90a7b5c1fe54ef320549681c04c948d7786cd4a8
@@ -8,6 +8,11 @@ module Delayed
8
8
  delegate :concurrent_index_creation_supported?, to: :class
9
9
  end
10
10
 
11
+ def exec_migration(...)
12
+ @migration_start = Delayed::Job.db_time_now
13
+ super
14
+ end
15
+
11
16
  module ClassMethods
12
17
  def concurrent_index_creation_supported?
13
18
  connection.index_algorithms.key?(:concurrently)
@@ -15,13 +20,17 @@ module Delayed
15
20
  end
16
21
 
17
22
  def upsert_index(*args, **opts)
18
- dir(:up) { _add_or_replace_index(*args, **opts) }
19
- dir(:down) { _drop_index_if_exists(*args, **opts) }
23
+ with_retry_loop(**opts) do
24
+ dir(:up) { _add_or_replace_index(*args, **opts) }
25
+ dir(:down) { _drop_index_if_exists(*args, **opts) }
26
+ end
20
27
  end
21
28
 
22
29
  def remove_index_if_exists(*args, **opts)
23
- dir(:up) { _drop_index_if_exists(*args, **opts) }
24
- dir(:down) { _add_or_replace_index(*args, **opts) }
30
+ with_retry_loop(**opts) do
31
+ dir(:up) { _drop_index_if_exists(*args, **opts) }
32
+ dir(:down) { _add_or_replace_index(*args, **opts) }
33
+ end
25
34
  end
26
35
 
27
36
  RETRY_EXCEPTIONS = [
@@ -43,7 +52,7 @@ module Delayed
43
52
  end
44
53
  end
45
54
 
46
- def with_timeouts(statement_timeout: 1.minute, lock_timeout: 5.seconds)
55
+ def with_timeouts(statement_timeout: 1.minute, lock_timeout: 5.seconds, **_opts)
47
56
  dir(:both) { set_timeouts!(statement_timeout: statement_timeout, lock_timeout: lock_timeout) }
48
57
  yield
49
58
  ensure
@@ -56,24 +65,15 @@ module Delayed
56
65
  index = _lookup_index(table, columns, **opts)
57
66
  if index && !_index_matches?(index, **opts)
58
67
  Delayed.logger.warn("Recreating index #{index.name} (is invalid or does not match desired options)")
59
- _drop_index(table, name: index.name, **opts)
68
+ remove_index(table, name: index.name)
60
69
  end
61
- _add_index(table, columns, **opts) if !index || !_index_matches?(index, **opts)
70
+ opts = opts.except(:wait_timeout, :statement_timeout, :lock_timeout)
71
+ add_index(table, columns, **opts) if !index || !_index_matches?(index, **opts)
62
72
  end
63
73
 
64
74
  def _drop_index_if_exists(table, columns, **opts)
65
75
  index = _lookup_index(table, columns, **opts)
66
- _drop_index(table, name: index.name, **opts) if index
67
- end
68
-
69
- def _add_index(*args, **opts)
70
- index_opts = opts.slice!(:wait_timeout, :statement_timeout, :lock_timeout)
71
- with_retry_loop(**opts) { add_index(*args, **index_opts) }
72
- end
73
-
74
- def _drop_index(table, name:, **opts)
75
- opts.slice!(:wait_timeout, :statement_timeout, :lock_timeout)
76
- with_retry_loop(**opts) { remove_index(table, name: name) }
76
+ remove_index(table, name: index.name) if index
77
77
  end
78
78
 
79
79
  def _lookup_index(table, columns, **opts)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delayed
4
- VERSION = '2.0.0'
4
+ VERSION = '2.0.2'
5
5
  end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'helper'
4
+
5
+ describe Delayed::Helpers::Migration do
6
+ let(:migration_class) do
7
+ Class.new(ActiveRecord::Migration[6.0]) do
8
+ include Delayed::Helpers::Migration
9
+
10
+ attr_accessor :migration_start
11
+
12
+ def connection
13
+ ActiveRecord::Base.connection
14
+ end
15
+
16
+ def reversible
17
+ direction = Object.new
18
+ def direction.up
19
+ yield if block_given?
20
+ end
21
+
22
+ def direction.down
23
+ yield if block_given?
24
+ end
25
+ yield direction
26
+ end
27
+ end
28
+ end
29
+
30
+ let(:migration) { migration_class.new }
31
+
32
+ before do
33
+ migration.migration_start = Delayed::Job.db_time_now
34
+ end
35
+
36
+ describe '#upsert_index retry behavior' do
37
+ it 'raises exception when wait_timeout is exceeded based on @migration_start' do
38
+ migration.migration_start = Delayed::Job.db_time_now - 6.minutes
39
+
40
+ allow(migration).to receive(:add_index).and_raise(ActiveRecord::LockWaitTimeout)
41
+ allow(migration.connection).to receive(:indexes).and_return([])
42
+
43
+ expect {
44
+ migration.upsert_index(:delayed_jobs, :name, wait_timeout: 5.minutes)
45
+ }.to raise_error(ActiveRecord::LockWaitTimeout)
46
+ end
47
+
48
+ it 're-checks for invalid index and drops it before retrying after timeout' do
49
+ add_index_calls = 0
50
+ remove_index_calls = 0
51
+ lookup_calls = 0
52
+
53
+ invalid_opts = ActiveRecord.version >= Gem::Version.new('7.1.0') ? { valid?: false } : { unique: true }
54
+ invalid_index = instance_double(
55
+ ActiveRecord::ConnectionAdapters::IndexDefinition,
56
+ name: 'test_idx',
57
+ columns: ['name'],
58
+ **invalid_opts,
59
+ )
60
+
61
+ allow(migration.connection).to receive(:indexes) do
62
+ lookup_calls += 1
63
+ lookup_calls == 2 ? [invalid_index] : []
64
+ end
65
+
66
+ allow(migration).to receive(:add_index) do |*_args|
67
+ add_index_calls += 1
68
+ raise ActiveRecord::StatementTimeout, 'timeout' if add_index_calls == 1
69
+ end
70
+
71
+ allow(migration).to receive(:remove_index) do |*_args|
72
+ remove_index_calls += 1
73
+ end
74
+
75
+ migration.upsert_index(:delayed_jobs, :name, name: 'test_idx', wait_timeout: 5.minutes)
76
+
77
+ expect(lookup_calls).to eq(3)
78
+ expect(remove_index_calls).to eq(1)
79
+ expect(add_index_calls).to eq(2)
80
+ end
81
+ end
82
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Griffith
@@ -19,7 +19,7 @@ authors:
19
19
  autorequire:
20
20
  bindir: bin
21
21
  cert_chain: []
22
- date: 2025-12-19 00:00:00.000000000 Z
22
+ date: 2026-01-05 00:00:00.000000000 Z
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
25
25
  name: activerecord
@@ -108,6 +108,7 @@ files:
108
108
  - spec/delayed/__snapshots__/job_spec.rb.snap
109
109
  - spec/delayed/__snapshots__/monitor_spec.rb.snap
110
110
  - spec/delayed/active_job_adapter_spec.rb
111
+ - spec/delayed/helpers/migration_spec.rb
111
112
  - spec/delayed/job_spec.rb
112
113
  - spec/delayed/monitor_spec.rb
113
114
  - spec/delayed/plugins/instrumentation_spec.rb
@@ -160,6 +161,7 @@ test_files:
160
161
  - spec/delayed/__snapshots__/job_spec.rb.snap
161
162
  - spec/delayed/__snapshots__/monitor_spec.rb.snap
162
163
  - spec/delayed/active_job_adapter_spec.rb
164
+ - spec/delayed/helpers/migration_spec.rb
163
165
  - spec/delayed/job_spec.rb
164
166
  - spec/delayed/monitor_spec.rb
165
167
  - spec/delayed/plugins/instrumentation_spec.rb