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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b01cc2376f8bcfa1908bdc642a51bd444420540eef7aa01dc403f13ea0b19c8
|
4
|
+
data.tar.gz: 0c09d3bc52ce84542fd50b119cef667714a6058d5fcf59f1be83af72318b3862
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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(
|
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
|
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"
|
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.
|
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-
|
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: []
|