safe-pg-migrations 1.2.2 → 1.2.3

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: d981ad3d9694961fa982676398e257817a2f20fb5ef28111c664da67d8caef19
4
- data.tar.gz: 7792a0f882fe9c594a1a0309bba12f03c2d0d18d5a0ef68fe49e1681da486ba6
3
+ metadata.gz: 8b01cc2376f8bcfa1908bdc642a51bd444420540eef7aa01dc403f13ea0b19c8
4
+ data.tar.gz: 0c09d3bc52ce84542fd50b119cef667714a6058d5fcf59f1be83af72318b3862
5
5
  SHA512:
6
- metadata.gz: a3d03df54c2a401ea4d7d178d66c8fc49c605cebc1e15f87a69e262df2bfc6433ef7ab86ae21e3ce88b52224a0c9fd14c3cf5f923e109ef06da2d55072fc7d3e
7
- data.tar.gz: b28101c7aedcdfb6fc3680ce9c5b14b459ed90fecf21aaf598942f6c91ebd757f1ed608f71c00e622ec9b24cf1f719a6450ae3ef28abd4f07476fd02f7c54242
6
+ metadata.gz: f7a822bbb6cc2e924c8da76ca1501cec16588b4972e850fd07e7fbc120e159dfef715a8293c3399454aa9072e2cc6c2da8927e6dc84f15c72670bb16182fe53c
7
+ data.tar.gz: 4821e1fb76ce6e868a2032eb0e53aceea8f745f31fce521333949c20143150bd03950187d7286d63d1d9c7269b6015f8b9be8e38833d3e6df659f2f8e5940902
data/README.md CHANGED
@@ -208,6 +208,8 @@ So you can actually check that the `CREATE INDEX` statement will be performed co
208
208
  ```ruby
209
209
  SafePgMigrations.config.safe_timeout = 5.seconds # Lock and statement timeout used for all DDL operations except from CREATE / DROP INDEX
210
210
 
211
+ SafePgMigrations.config.blocking_activity_logger_verbose = true # Outputs the raw blocking queries on timeout. When false, outputs information about the lock instead
212
+
211
213
  SafePgMigrations.config.blocking_activity_logger_margin = 1.second # Delay to output blocking queries before timeout. Must be shorter than safe_timeout
212
214
 
213
215
  SafePgMigrations.config.batch_size = 1000 # Size of the batches used for backfilling when adding a column with a default value pre-PG11
@@ -6,6 +6,7 @@ module SafePgMigrations
6
6
  class Configuration
7
7
  attr_accessor :safe_timeout
8
8
  attr_accessor :blocking_activity_logger_margin
9
+ attr_accessor :blocking_activity_logger_verbose
9
10
  attr_accessor :batch_size
10
11
  attr_accessor :retry_delay
11
12
  attr_accessor :max_tries
@@ -13,6 +14,7 @@ module SafePgMigrations
13
14
  def initialize
14
15
  self.safe_timeout = 5.seconds
15
16
  self.blocking_activity_logger_margin = 1.second
17
+ self.blocking_activity_logger_verbose = true
16
18
  self.batch_size = 1000
17
19
  self.retry_delay = 1.minute
18
20
  self.max_tries = 5
@@ -2,27 +2,18 @@
2
2
 
3
3
  module SafePgMigrations
4
4
  module BlockingActivityLogger
5
- SELECT_BLOCKING_QUERIES_SQL = <<~SQL.squish
6
- SELECT blocking_activity.query, blocked_activity.xact_start as start
7
- FROM pg_catalog.pg_locks blocked_locks
8
- JOIN pg_catalog.pg_stat_activity blocked_activity
9
- ON blocked_activity.pid = blocked_locks.pid
10
- JOIN pg_catalog.pg_locks blocking_locks
11
- ON blocking_locks.locktype = blocked_locks.locktype
12
- AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
13
- AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
14
- AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
15
- AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
16
- AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
17
- AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
18
- AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
19
- AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
20
- AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
21
- AND blocking_locks.pid != blocked_locks.pid
22
- JOIN pg_catalog.pg_stat_activity blocking_activity
23
- ON blocking_activity.pid = blocking_locks.pid
24
- WHERE blocked_locks.pid = %d
25
- SQL
5
+ FILTERED_COLUMNS = %w[
6
+ blocked_activity.xact_start
7
+ blocked_locks.locktype
8
+ blocked_locks.mode
9
+ blocking_activity.pid
10
+ blocked_locks.transactionid
11
+ ].freeze
12
+
13
+ VERBOSE_COLUMNS = %w[
14
+ blocking_activity.query
15
+ blocked_activity.xact_start
16
+ ].freeze
26
17
 
27
18
  %i[
28
19
  add_column remove_column add_foreign_key remove_foreign_key change_column_default change_column_null create_table
@@ -34,6 +25,32 @@ module SafePgMigrations
34
25
 
35
26
  private
36
27
 
28
+ def select_blocking_queries_sql
29
+ columns = SafePgMigrations.config.blocking_activity_logger_verbose ? VERBOSE_COLUMNS : FILTERED_COLUMNS
30
+
31
+ <<~SQL.squish
32
+ SELECT #{columns.join(', ')}
33
+ FROM pg_catalog.pg_locks blocked_locks
34
+ JOIN pg_catalog.pg_stat_activity blocked_activity
35
+ ON blocked_activity.pid = blocked_locks.pid
36
+ JOIN pg_catalog.pg_locks blocking_locks
37
+ ON blocking_locks.locktype = blocked_locks.locktype
38
+ AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
39
+ AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
40
+ AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
41
+ AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
42
+ AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
43
+ AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
44
+ AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
45
+ AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
46
+ AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
47
+ AND blocking_locks.pid != blocked_locks.pid
48
+ JOIN pg_catalog.pg_stat_activity blocking_activity
49
+ ON blocking_activity.pid = blocking_locks.pid
50
+ WHERE blocked_locks.pid = %d
51
+ SQL
52
+ end
53
+
37
54
  def log_blocking_queries
38
55
  delay_before_logging =
39
56
  SafePgMigrations.config.safe_timeout - SafePgMigrations.config.blocking_activity_logger_margin
@@ -41,7 +58,7 @@ module SafePgMigrations
41
58
  blocking_queries_retriever_thread =
42
59
  Thread.new do
43
60
  sleep delay_before_logging
44
- SafePgMigrations.alternate_connection.query(SELECT_BLOCKING_QUERIES_SQL % raw_connection.backend_pid)
61
+ SafePgMigrations.alternate_connection.query(select_blocking_queries_sql % raw_connection.backend_pid)
45
62
  end
46
63
 
47
64
  yield
@@ -66,7 +83,7 @@ module SafePgMigrations
66
83
  "Statement was being blocked by the following #{'query'.pluralize(queries.size)}:", true
67
84
  )
68
85
  SafePgMigrations.say '', true
69
- queries.each { |query, start_time| SafePgMigrations.say "#{format_start_time start_time}: #{query}", true }
86
+ output_blocking_queries(queries)
70
87
  SafePgMigrations.say(
71
88
  'Beware, some of those queries might run in a transaction. In this case the locking query might be '\
72
89
  'located elsewhere in the transaction',
@@ -78,6 +95,22 @@ module SafePgMigrations
78
95
  raise
79
96
  end
80
97
 
98
+ def output_blocking_queries(queries)
99
+ if SafePgMigrations.config.blocking_activity_logger_verbose
100
+ queries.each { |query, start_time| SafePgMigrations.say "#{format_start_time start_time}: #{query}", true }
101
+ else
102
+ queries.each do |start_time, locktype, mode, pid, transactionid|
103
+ SafePgMigrations.say(
104
+ "#{format_start_time(start_time)}: lock type: #{locktype || 'null'}, " \
105
+ "lock mode: #{mode || 'null'}, " \
106
+ "lock pid: #{pid || 'null'}, " \
107
+ "lock transactionid: #{transactionid || 'null'}",
108
+ true
109
+ )
110
+ end
111
+ end
112
+ end
113
+
81
114
  def format_start_time(start_time, reference_time = Time.now)
82
115
  duration = (reference_time - start_time).round
83
116
  "transaction started #{duration} #{'second'.pluralize(duration)} ago"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SafePgMigrations
4
- VERSION = '1.2.2'
4
+ VERSION = '1.2.3'
5
5
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safe-pg-migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthieu Prat
8
8
  - Romain Choquet
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-04-13 00:00:00.000000000 Z
12
+ date: 2021-04-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -174,7 +174,7 @@ homepage: https://github.com/doctolib/safe-pg-migrations
174
174
  licenses:
175
175
  - MIT
176
176
  metadata: {}
177
- post_install_message:
177
+ post_install_message:
178
178
  rdoc_options: []
179
179
  require_paths:
180
180
  - lib
@@ -189,9 +189,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
189
  - !ruby/object:Gem::Version
190
190
  version: '0'
191
191
  requirements: []
192
- rubyforge_project:
192
+ rubyforge_project:
193
193
  rubygems_version: 2.7.3
194
- signing_key:
194
+ signing_key:
195
195
  specification_version: 4
196
196
  summary: Make your PG migrations safe.
197
197
  test_files: []