nandi 3.0.0 → 3.2.0

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: 986532981584b1518a8422a2cc212ed963782fb31554012a0e2b4da50bf8a3db
4
- data.tar.gz: 282b4f7c95256f6a8af1090b82a2324d0cc12e4570bf22608c219d8486cb5334
3
+ metadata.gz: '068eff75d4f385070e3da2d3738019cf4e6be7554a16e235f3701e3c0db79419'
4
+ data.tar.gz: cfe9e766d00073ab040888cad17bedb8c4b2b294d7e353d5298a9ccce9a130f2
5
5
  SHA512:
6
- metadata.gz: 7788cca1a5ca77b8e8e04decc6819b41078936452f3ab2cae00a3b35ca6c338f4fb4870e2d8eb11f4f3109029c41a2ccd327fb980417e1b95c1bf48644bca23e
7
- data.tar.gz: 2331b4022d381b2863ecbf2429365aa2870fb39386fde1cb0aa27ea8800fc3c7777490896a2d55af95696d8b0457c2f485890f5dcd8878019f1a50b2ea28af09
6
+ metadata.gz: 86c97f9217b2fc3819d8204f80e0f29d7d00e63b3929b40cd684d66b6e701d97b69bb1094714ef8e33bf3c451d67fb31803a18c6625ac2f2a06e4c159ff2dd98
7
+ data.tar.gz: 83b8831e08ddcfedf0e558acf5b4813866605757f17d3ca74ec21f9815f774f8207d0b2e7dd1d50aa87674c39e06420fac106454996b2a8f37eb4a660a6e1b95
data/README.md CHANGED
@@ -566,6 +566,9 @@ These options can be set individually for each database. **All are optional** -
566
566
  - `access_exclusive_statement_timeout_limit`: Maximum allowed statement timeout (default: 1,500ms)
567
567
  - `concurrent_lock_timeout_limit`: Minimum timeout for concurrent operations (default: 3,600,000ms / 1 hour)
568
568
  - `concurrent_statement_timeout_limit`: Minimum statement timeout for concurrent operations (default: 3,600,000ms / 1 hour)
569
+ - `concurrent_lock_timeout`: Lock timeout for concurrent operations (`add_index`/`remove_index`). When set, concurrent migrations use `set_lock_timeout` instead of `disable_lock_timeout!`. Default: `nil` (timeout disabled)
570
+ - `concurrent_statement_timeout`: Statement timeout for concurrent operations. When set, concurrent migrations use `set_statement_timeout` instead of `disable_statement_timeout!`. Default: `nil` (timeout disabled)
571
+ - `table_overrides`: Per-table overrides of `concurrent_lock_timeout`/`concurrent_statement_timeout`, keyed by table name. Falls back to the database-level value for any table (or key) not listed
569
572
 
570
573
  **Global options** (set via config accessors):
571
574
 
@@ -621,6 +624,20 @@ Nandi.configure do |config|
621
624
  migration
622
625
  end
623
626
  end
627
+
628
+ # Give a specific, huge table a longer concurrent statement/lock timeout than
629
+ # the database-wide default, without loosening it for every other table.
630
+ Nandi.configure do |config|
631
+ config.register_database(:primary,
632
+ concurrent_lock_timeout: 120_000, # 2 minutes, database-wide default
633
+ concurrent_statement_timeout: 600_000, # 10 minutes, database-wide default
634
+ table_overrides: {
635
+ payments: {
636
+ concurrent_lock_timeout: 300_000, # 5 minutes
637
+ concurrent_statement_timeout: 1_800_000, # 30 minutes
638
+ },
639
+ })
640
+ end
624
641
  ```
625
642
 
626
643
  ### Directory Structure
@@ -50,7 +50,7 @@ module Nandi
50
50
  end
51
51
 
52
52
  def migration
53
- @migration ||= class_name.camelize.constantize.new(Nandi.validator)
53
+ @migration ||= class_name.camelize.constantize.new(Nandi.validator, database_name: db_name)
54
54
  end
55
55
 
56
56
  def compiled_digest
data/lib/nandi/config.rb CHANGED
@@ -84,8 +84,8 @@ module Nandi
84
84
  def access_exclusive_statement_timeout_max(database_name = nil) = config(database_name).access_exclusive_statement_timeout_max
85
85
  def concurrent_lock_timeout_min(database_name = nil) = config(database_name).concurrent_lock_timeout_min
86
86
  def concurrent_statement_timeout_min(database_name = nil) = config(database_name).concurrent_statement_timeout_min
87
- def concurrent_lock_timeout(database_name = nil) = config(database_name).concurrent_lock_timeout
88
- def concurrent_statement_timeout(database_name = nil) = config(database_name).concurrent_statement_timeout
87
+ def concurrent_lock_timeout(database_name = nil, table_name = nil) = config(database_name).concurrent_lock_timeout(table_name)
88
+ def concurrent_statement_timeout(database_name = nil, table_name = nil) = config(database_name).concurrent_statement_timeout(table_name)
89
89
  # rubocop:enable Layout/LineLength
90
90
 
91
91
  # Delegate setter methods to the default database for backwards compatibility
@@ -69,12 +69,18 @@ module Nandi
69
69
  end
70
70
 
71
71
  # @param validator [Nandi::Validator]
72
- def initialize(validator)
72
+ # @param database_name [Symbol, nil] The database this migration is being compiled
73
+ # for. Used to resolve per-database config. Defaults to the default database.
74
+ def initialize(validator, database_name: nil)
73
75
  @validator = validator
76
+ @database_name = database_name
74
77
  @instructions = Hash.new { |h, k| h[k] = InstructionSet.new([]) }
75
78
  validate
76
79
  end
77
80
 
81
+ # @api private
82
+ attr_reader :database_name
83
+
78
84
  # @api private
79
85
  def up_instructions
80
86
  compile_instructions(:up)
@@ -331,7 +337,7 @@ module Nandi
331
337
 
332
338
  def disable_lock_timeout?
333
339
  if self.class.lock_timeout.nil?
334
- strictest_lock == LockWeights::SHARE && Nandi.config.concurrent_lock_timeout.nil?
340
+ strictest_lock == LockWeights::SHARE && Nandi.config.concurrent_lock_timeout(database_name, table).nil?
335
341
  else
336
342
  false
337
343
  end
@@ -339,7 +345,7 @@ module Nandi
339
345
 
340
346
  def disable_statement_timeout?
341
347
  if self.class.statement_timeout.nil?
342
- strictest_lock == LockWeights::SHARE && Nandi.config.concurrent_statement_timeout.nil?
348
+ strictest_lock == LockWeights::SHARE && Nandi.config.concurrent_statement_timeout(database_name, table).nil?
343
349
  else
344
350
  false
345
351
  end
@@ -354,7 +360,7 @@ module Nandi
354
360
  end
355
361
 
356
362
  def mixins
357
- (up_instructions + down_instructions).inject([]) do |mixins, i|
363
+ all_instructions.inject([]) do |mixins, i|
358
364
  i.respond_to?(:mixins) ? [*mixins, *i.mixins] : mixins
359
365
  end.uniq
360
366
  end
@@ -377,20 +383,33 @@ module Nandi
377
383
 
378
384
  def default_statement_timeout
379
385
  if strictest_lock == LockWeights::SHARE
380
- Nandi.config.concurrent_statement_timeout || Nandi.config.access_exclusive_statement_timeout
386
+ Nandi.config.concurrent_statement_timeout(database_name, table) ||
387
+ Nandi.config.access_exclusive_statement_timeout(database_name)
381
388
  else
382
- Nandi.config.access_exclusive_statement_timeout
389
+ Nandi.config.access_exclusive_statement_timeout(database_name)
383
390
  end
384
391
  end
385
392
 
386
393
  def default_lock_timeout
387
394
  if strictest_lock == LockWeights::SHARE
388
- Nandi.config.concurrent_lock_timeout || Nandi.config.access_exclusive_lock_timeout
395
+ Nandi.config.concurrent_lock_timeout(database_name, table) ||
396
+ Nandi.config.access_exclusive_lock_timeout(database_name)
389
397
  else
390
- Nandi.config.access_exclusive_lock_timeout
398
+ Nandi.config.access_exclusive_lock_timeout(database_name)
391
399
  end
392
400
  end
393
401
 
402
+ # The table this migration modifies, if any. Validator guarantees a migration
403
+ # modifies at most one table, so this is unambiguous.
404
+ def table
405
+ instruction_with_table = all_instructions.find { |i| i.respond_to?(:table) }
406
+ instruction_with_table&.table&.to_sym
407
+ end
408
+
409
+ def all_instructions
410
+ up_instructions + down_instructions
411
+ end
412
+
394
413
  def invoke_custom_method(name, ...)
395
414
  klass = Nandi.config.custom_methods[name]
396
415
  current_instructions << klass.new(...)
@@ -54,14 +54,24 @@ module Nandi
54
54
  # The default lock timeout for migrations that take place concurrently
55
55
  # (eg. add_index, remove_index). When set, concurrent migrations will use
56
56
  # set_lock_timeout instead of disable_lock_timeout!. Default: nil (disabled).
57
+ # Can be overridden for a specific table via `table_overrides`.
58
+ # @param table_name [Symbol, String, nil]
57
59
  # @return [Integer, nil]
58
- attr_accessor :concurrent_lock_timeout
60
+ def concurrent_lock_timeout(table_name = nil)
61
+ table_override(table_name, :concurrent_lock_timeout) || @concurrent_lock_timeout
62
+ end
63
+ attr_writer :concurrent_lock_timeout
59
64
 
60
65
  # The default statement timeout for migrations that take place concurrently
61
66
  # (eg. add_index, remove_index). When set, concurrent migrations will use
62
67
  # set_statement_timeout instead of disable_statement_timeout!. Default: nil (disabled).
68
+ # Can be overridden for a specific table via `table_overrides`.
69
+ # @param table_name [Symbol, String, nil]
63
70
  # @return [Integer, nil]
64
- attr_accessor :concurrent_statement_timeout
71
+ def concurrent_statement_timeout(table_name = nil)
72
+ table_override(table_name, :concurrent_statement_timeout) || @concurrent_statement_timeout
73
+ end
74
+ attr_writer :concurrent_statement_timeout
65
75
 
66
76
  # The directory for output files. Default: `db/migrate`
67
77
  # @return [String]
@@ -121,6 +131,17 @@ module Nandi
121
131
  config[:concurrent_statement_timeout_min] || DEFAULT_CONCURRENT_STATEMENT_TIMEOUT_MIN
122
132
  @concurrent_lock_timeout = config[:concurrent_lock_timeout]
123
133
  @concurrent_statement_timeout = config[:concurrent_statement_timeout]
134
+ @table_overrides = normalize_table_overrides(config[:table_overrides])
135
+ end
136
+
137
+ def normalize_table_overrides(table_overrides)
138
+ (table_overrides || {}).transform_keys(&:to_sym)
139
+ end
140
+
141
+ def table_override(table_name, key)
142
+ return nil if table_name.nil?
143
+
144
+ @table_overrides.dig(table_name.to_sym, key)
124
145
  end
125
146
 
126
147
  def path_prefix(name, default)
@@ -43,11 +43,11 @@ module Nandi
43
43
  end
44
44
 
45
45
  def statement_timeout_maximum
46
- Nandi.config.access_exclusive_statement_timeout_max
46
+ Nandi.config.access_exclusive_statement_timeout_max(migration.database_name)
47
47
  end
48
48
 
49
49
  def lock_timeout_maximum
50
- Nandi.config.access_exclusive_lock_timeout_max
50
+ Nandi.config.access_exclusive_lock_timeout_max(migration.database_name)
51
51
  end
52
52
  end
53
53
  end
@@ -53,11 +53,11 @@ module Nandi
53
53
  end
54
54
 
55
55
  def minimum_lock_timeout
56
- Nandi.config.concurrent_lock_timeout_min
56
+ Nandi.config.concurrent_lock_timeout_min(migration.database_name)
57
57
  end
58
58
 
59
59
  def minimum_statement_timeout
60
- Nandi.config.concurrent_statement_timeout_min
60
+ Nandi.config.concurrent_statement_timeout_min(migration.database_name)
61
61
  end
62
62
  end
63
63
  end
data/lib/nandi/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nandi
4
- VERSION = "3.0.0"
4
+ VERSION = "3.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nandi
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GoCardless Engineering
@@ -180,7 +180,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
180
180
  - !ruby/object:Gem::Version
181
181
  version: '0'
182
182
  requirements: []
183
- rubygems_version: 4.0.10
183
+ rubygems_version: 4.0.9
184
184
  specification_version: 4
185
185
  summary: Fear-free migrations for PostgreSQL
186
186
  test_files: []