safe-pg-migrations 1.2.2 → 1.2.3

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