safe-pg-migrations 0.0.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +93 -13
- data/lib/safe-pg-migrations/base.rb +14 -7
- data/lib/safe-pg-migrations/configuration.rb +19 -4
- data/lib/safe-pg-migrations/plugins/blocking_activity_logger.rb +19 -3
- data/lib/safe-pg-migrations/plugins/statement_insurer.rb +23 -13
- data/lib/safe-pg-migrations/plugins/verbose_sql_logger.rb +43 -0
- data/lib/safe-pg-migrations/railtie.rb +1 -1
- data/lib/safe-pg-migrations/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3e47cc5a8440b59b3e25dc7a5e99a9212c4709c
|
4
|
+
data.tar.gz: 7347fdd053c1edd34b3ec58d9021b126ec794eb3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74058e22a0e55ae44e29b8e74096bf0b4bf6b7c83a7fafce8c6aa3595c50bafec2d93c6ce502d304f89b44e236a3f3770fac91ff7e9bb449a3289cca0a06ab89
|
7
|
+
data.tar.gz: 7a38389555cb2cd8c0271882389aed8e27b1d22ef7cb16976c729041ef315803ad7de0a71400f478d50c7c741e1b10a5a37109940de5a5e7a8809800eecdff25
|
data/README.md
CHANGED
@@ -28,7 +28,7 @@ class AddAdminToUsers < ActiveRecord::Migration[5.2]
|
|
28
28
|
end
|
29
29
|
```
|
30
30
|
|
31
|
-
If the `users` table is large, running this migration on a live Postgres database will likely cause downtime. **Safe PG Migrations** hooks into Active Record so that the following gets executed instead:
|
31
|
+
If the `users` table is large, running this migration on a live Postgres 9 database will likely cause downtime. **Safe PG Migrations** hooks into Active Record so that the following gets executed instead:
|
32
32
|
|
33
33
|
```rb
|
34
34
|
class AddAdminToUsers < ActiveRecord::Migration[5.2]
|
@@ -69,19 +69,19 @@ Active Record means developers don't have to be proficient in SQL to interact wi
|
|
69
69
|
|
70
70
|
### Lock timeout
|
71
71
|
|
72
|
-
Most DDL operations (e.g. adding a column, removing a column or adding a default value to a column) take an `ACCESS EXCLUSIVE` lock on the table they are altering. While these operations wait to acquire their lock, other statements are blocked. Before running a migration, **Safe PG Migrations** sets a short lock timeout so that statements are not blocked for too long.
|
72
|
+
Most DDL operations (e.g. adding a column, removing a column or adding a default value to a column) take an `ACCESS EXCLUSIVE` lock on the table they are altering. While these operations wait to acquire their lock, other statements are blocked. Before running a migration, **Safe PG Migrations** sets a short lock timeout (default to 5 seconds) so that statements are not blocked for too long.
|
73
73
|
|
74
74
|
See [PostgreSQL Alter Table and Long Transactions](http://www.joshuakehn.com/2017/9/9/postgresql-alter-table-and-long-transactions.html) and [Migrations and Long Transactions](https://www.fin.com/post/2018/1/migrations-and-long-transactions) for detailed explanations of the matter.
|
75
75
|
|
76
76
|
### Statement timeout
|
77
77
|
|
78
|
-
Adding a foreign key or a not-null constraint can take a lot of time on a large table. The problem is that those operations take `ACCESS EXCLUSIVE` locks. We clearly don't want them to hold these locks for too long. Thus, **Safe PG Migrations** runs them with a short statement timeout.
|
78
|
+
Adding a foreign key or a not-null constraint can take a lot of time on a large table. The problem is that those operations take `ACCESS EXCLUSIVE` locks. We clearly don't want them to hold these locks for too long. Thus, **Safe PG Migrations** runs them with a short statement timeout (default to 5 seconds).
|
79
79
|
|
80
80
|
See [Zero-downtime Postgres migrations - the hard parts](https://gocardless.com/blog/zero-downtime-postgres-migrations-the-hard-parts/) for a detailed explanation on the subject.
|
81
81
|
|
82
82
|
### Prevent wrapping migrations in transaction
|
83
83
|
|
84
|
-
When **Safe PG Migrations** is
|
84
|
+
When **Safe PG Migrations** is used, migrations are not wrapped in a transaction. This is for several reasons:
|
85
85
|
|
86
86
|
- We want to release locks as soon as possible.
|
87
87
|
- In order to be able to retry statements that have failed because of a lock timeout, we have to be outside a transaction.
|
@@ -91,6 +91,8 @@ Note that if a migration fails, it won't be rollbacked. This can result in migra
|
|
91
91
|
|
92
92
|
### Safe `add_column`
|
93
93
|
|
94
|
+
#### Pre Postgres 11 behavior
|
95
|
+
|
94
96
|
Adding a column with a default value and a not-null constraint is [dangerous](https://wework.github.io/data/2015/11/05/add-columns-with-default-values-to-large-tables-in-rails-postgres/).
|
95
97
|
|
96
98
|
**Safe PG Migrations** makes it safe by:
|
@@ -102,18 +104,95 @@ Adding a column with a default value and a not-null constraint is [dangerous](ht
|
|
102
104
|
|
103
105
|
Note: the addition of the not null constraint may timeout. In that case, you may want to add the not-null constraint as initially not valid and validate it in a separate statement. See [Adding a not-null constraint on Postgres with minimal locking](https://medium.com/doctolib-engineering/adding-a-not-null-constraint-on-pg-faster-with-minimal-locking-38b2c00c4d1c).
|
104
106
|
|
107
|
+
#### Postgres 11 behavior
|
108
|
+
|
109
|
+
**Safe PG Migrations** gracefully handle the upgrade to PG11 by **not** backfilling default value for existing rows, as the [database engine is now natively handling it](https://www.postgresql.org/docs/11/ddl-alter.html#DDL-ALTER-ADDING-A-COLUMN).
|
110
|
+
|
111
|
+
Beware though, when adding a volatile default value:
|
112
|
+
```ruby
|
113
|
+
add_column :users, :created_at, default: 'clock_timestamp()'
|
114
|
+
```
|
115
|
+
PG will still needs to update every row of the table, and will most likely statement timeout for big table. In this case, your best bet is to add the column without default, set the default, and backfill existing rows.
|
116
|
+
|
105
117
|
### Concurrent indexes
|
106
118
|
|
107
119
|
Creating an index requires a `SHARE` lock on the target table which blocks all write on the table while the index is created (which can take some time on a large table). This is usually not practical in a live environment. Thus, **Safe PG Migrations** ensures indexes are created concurrently.
|
108
120
|
|
121
|
+
As `CREATE INDEX CONCURRENTLY` and `DROP INDEX CONCURRENTLY` are non-blocking operations (ie: read/write operations on the table are still possible), **Safe PG Migrations** sets a lock timeout to 30 seconds for those 2 specific statements.
|
122
|
+
|
123
|
+
If you still get lock timeout while adding / removing indexes, it might be for one of those reasons:
|
124
|
+
|
125
|
+
- Long-running queries are active on the table. To create / remove an index, PG needs to wait for the queries that are actually running to finish before starting the index creation / removal. The blocking activity logger might help you to pinpoint the culprit queries.
|
126
|
+
- A vacuum / autovacuum is running on the table, holding a ShareUpdateExclusiveLock, you are most likely out of luck for the current migration, but you may try to [optimize your autovacuums settings](https://www.percona.com/blog/2018/08/10/tuning-autovacuum-in-postgresql-and-autovacuum-internals/).
|
127
|
+
|
128
|
+
|
109
129
|
### Retry after lock timeout
|
110
130
|
|
111
|
-
When a statement fails with a lock timeout, **Safe PG Migrations** retries
|
131
|
+
When a statement fails with a lock timeout, **Safe PG Migrations** retries it (5 times max) [list of retryable statments](https://github.com/doctolib/safe-pg-migrations/blob/66933256252b6bbf12e404b829a361dbba30e684/lib/safe-pg-migrations/plugins/statement_retrier.rb#L5)
|
112
132
|
|
113
133
|
### Blocking activity logging
|
114
134
|
|
115
135
|
If a statement fails with a lock timeout, **Safe PG Migrations** will try to tell you what was the blocking statement.
|
116
136
|
|
137
|
+
### Verbose SQL logging
|
138
|
+
|
139
|
+
For any operation, **Safe PG Migrations** can output the performed SQL queries. This feature is enabled by default in a production Rails environment. If you want to explicit enable it, for example in your development environment you can use:
|
140
|
+
```bash
|
141
|
+
export SAFE_PG_MIGRATIONS_VERBOSE=1
|
142
|
+
```
|
143
|
+
|
144
|
+
Instead of the traditional output:
|
145
|
+
```ruby
|
146
|
+
add_index :users, :age
|
147
|
+
|
148
|
+
== 20191215132355 SampleIndex: migrating ======================================
|
149
|
+
-- add_index(:users, :age)
|
150
|
+
-> add_index("users", :age, {:algorithm=>:concurrently})
|
151
|
+
-> 0.0175s
|
152
|
+
== 20191215132355 SampleIndex: migrated (0.0200s) =============================
|
153
|
+
```
|
154
|
+
**Sage PG Migrations** will output the following logs:
|
155
|
+
```ruby
|
156
|
+
add_index :users, :age
|
157
|
+
|
158
|
+
== 20191215132355 SampleIndex: migrating ======================================
|
159
|
+
(0.3ms) SHOW lock_timeout
|
160
|
+
(0.3ms) SET lock_timeout TO '5s'
|
161
|
+
-- add_index(:users, :age)
|
162
|
+
-> add_index("users", :age, {:algorithm=>:concurrently})
|
163
|
+
(0.3ms) SHOW statement_timeout
|
164
|
+
(0.3ms) SET statement_timeout TO 0
|
165
|
+
(0.3ms) SHOW lock_timeout
|
166
|
+
(0.3ms) SET lock_timeout TO '30s'
|
167
|
+
(3.5ms) CREATE INDEX CONCURRENTLY "index_users_on_age" ON "users" ("age")
|
168
|
+
(0.3ms) SET lock_timeout TO '5s'
|
169
|
+
(0.2ms) SET statement_timeout TO '1min'
|
170
|
+
-> 0.0093s
|
171
|
+
(0.2ms) SET lock_timeout TO '0'
|
172
|
+
== 20191215132355 SampleIndex: migrated (0.0114s) =============================
|
173
|
+
```
|
174
|
+
So you can actually check that the `CREATE INDEX` statement will be performed concurrently, without any statement timeout and with a lock timeout of 30 seconds.
|
175
|
+
|
176
|
+
*Nb: The `SHOW` statements are used by **Safe PG Migrations** to query settings for their original values in order to restore them after the work is done*
|
177
|
+
|
178
|
+
## Configuration
|
179
|
+
|
180
|
+
**Safe PG Migrations** can be customized, here is an example of a Rails initializer (the values are the default ones):
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
SafePgMigrations.config.safe_timeout = 5.seconds # Lock and statement timeout used for all DDL operations except from CREATE / DROP INDEX
|
184
|
+
|
185
|
+
SafePgMigrations.config.index_lock_timeout = 30.seconds # Lock timeout used for CREATE / DROP INDEX
|
186
|
+
|
187
|
+
SafePgMigrations.config.blocking_activity_logger_margin = 1.second # Delay to output blocking queries before timeout. Must be smaller than safe_timeout and index_lock_timeout
|
188
|
+
|
189
|
+
SafePgMigrations.config.batch_size = 1000 # Size of the batches used for backfilling when adding a column with a default value pre-PG11
|
190
|
+
|
191
|
+
SafePgMigrations.config.retry_delay = 1.minute # Delay between retries for retryable statements
|
192
|
+
|
193
|
+
SafePgMigrations.config.max_tries = 5 # Number of retries before abortion of the migration
|
194
|
+
```
|
195
|
+
|
117
196
|
## Runnings tests
|
118
197
|
|
119
198
|
```bash
|
@@ -142,11 +221,12 @@ Alternatives:
|
|
142
221
|
|
143
222
|
Interesting reads:
|
144
223
|
|
145
|
-
- https://www.citusdata.com/blog/2018/02/22/seven-tips-for-dealing-with-postgres-locks/
|
146
|
-
-
|
147
|
-
|
148
|
-
-
|
149
|
-
- https://
|
150
|
-
- https://
|
151
|
-
- https://
|
152
|
-
- https://
|
224
|
+
- [When Postgres blocks: 7 tips for dealing with locks](https://www.citusdata.com/blog/2018/02/22/seven-tips-for-dealing-with-postgres-locks/)
|
225
|
+
- [Migrations and Long Transactions in Postgres
|
226
|
+
](https://www.fin.com/post/2018/1/migrations-and-long-transactions)
|
227
|
+
- [PostgreSQL Alter Table and Long Transactions](http://www.joshuakehn.com/2017/9/9/postgresql-alter-table-and-long-transactions.html)
|
228
|
+
- [Adding a NOT NULL CONSTRAINT on PG Faster with Minimal Locking](https://medium.com/doctolib-engineering/adding-a-not-null-constraint-on-pg-faster-with-minimal-locking-38b2c00c4d1c)
|
229
|
+
- [Adding columns with default values to really large tables in Postgres + Rails](https://wework.github.io/data/2015/11/05/add-columns-with-default-values-to-large-tables-in-rails-postgres/)
|
230
|
+
- [Rails migrations with no downtime](https://pedro.herokuapp.com/past/2011/7/13/rails_migrations_with_no_downtime/)
|
231
|
+
- [Safe Operations For High Volume PostgreSQL](https://www.braintreepayments.com/blog/safe-operations-for-high-volume-postgresql/)
|
232
|
+
- [Rails Migrations with Zero Downtime](https://blog.codeship.com/rails-migrations-zero-downtime/)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'safe-pg-migrations/configuration'
|
4
|
+
require 'safe-pg-migrations/plugins/verbose_sql_logger'
|
4
5
|
require 'safe-pg-migrations/plugins/blocking_activity_logger'
|
5
6
|
require 'safe-pg-migrations/plugins/statement_insurer'
|
6
7
|
require 'safe-pg-migrations/plugins/statement_retrier'
|
@@ -16,17 +17,24 @@ module SafePgMigrations
|
|
16
17
|
].freeze
|
17
18
|
|
18
19
|
class << self
|
19
|
-
attr_reader :current_migration
|
20
|
-
attr_accessor :enabled
|
20
|
+
attr_reader :current_migration, :pg_version_num
|
21
21
|
|
22
22
|
def setup_and_teardown(migration, connection)
|
23
|
+
@pg_version_num = get_pg_version_num(connection)
|
23
24
|
@alternate_connection = nil
|
24
25
|
@current_migration = migration
|
26
|
+
stdout_sql_logger = VerboseSqlLogger.new.setup if verbose?
|
25
27
|
PLUGINS.each { |plugin| connection.extend(plugin) }
|
26
|
-
|
28
|
+
|
29
|
+
connection.with_setting(:lock_timeout, SafePgMigrations.config.pg_safe_timeout) { yield }
|
27
30
|
ensure
|
28
31
|
close_alternate_connection
|
29
32
|
@current_migration = nil
|
33
|
+
stdout_sql_logger&.teardown
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_pg_version_num(connection)
|
37
|
+
connection.query_value('SHOW server_version_num').to_i
|
30
38
|
end
|
31
39
|
|
32
40
|
def alternate_connection
|
@@ -50,9 +58,8 @@ module SafePgMigrations
|
|
50
58
|
say "#{method}(#{args.map(&:inspect) * ', '})", true
|
51
59
|
end
|
52
60
|
|
53
|
-
def
|
54
|
-
return ENV['
|
55
|
-
return enabled unless enabled.nil?
|
61
|
+
def verbose?
|
62
|
+
return ENV['SAFE_PG_MIGRATIONS_VERBOSE'] == '1' if ENV['SAFE_PG_MIGRATIONS_VERBOSE']
|
56
63
|
return Rails.env.production? if defined?(Rails)
|
57
64
|
|
58
65
|
false
|
@@ -71,7 +78,7 @@ module SafePgMigrations
|
|
71
78
|
end
|
72
79
|
|
73
80
|
def disable_ddl_transaction
|
74
|
-
|
81
|
+
true
|
75
82
|
end
|
76
83
|
|
77
84
|
SAFE_METHODS = %i[execute add_column add_index add_reference add_belongs_to change_column_null].freeze
|
@@ -5,17 +5,32 @@ require 'active_support/core_ext/numeric/time'
|
|
5
5
|
module SafePgMigrations
|
6
6
|
class Configuration
|
7
7
|
attr_accessor :safe_timeout
|
8
|
-
attr_accessor :
|
8
|
+
attr_accessor :index_lock_timeout
|
9
|
+
attr_accessor :blocking_activity_logger_margin
|
9
10
|
attr_accessor :batch_size
|
10
11
|
attr_accessor :retry_delay
|
11
12
|
attr_accessor :max_tries
|
12
13
|
|
13
14
|
def initialize
|
14
|
-
self.safe_timeout =
|
15
|
-
self.
|
15
|
+
self.safe_timeout = 5.seconds
|
16
|
+
self.index_lock_timeout = 30.seconds
|
17
|
+
self.blocking_activity_logger_margin = 1.second
|
16
18
|
self.batch_size = 1000
|
17
|
-
self.retry_delay =
|
19
|
+
self.retry_delay = 1.minute
|
18
20
|
self.max_tries = 5
|
19
21
|
end
|
22
|
+
|
23
|
+
def pg_safe_timeout
|
24
|
+
pg_duration(safe_timeout)
|
25
|
+
end
|
26
|
+
|
27
|
+
def pg_index_lock_timeout
|
28
|
+
pg_duration(index_lock_timeout)
|
29
|
+
end
|
30
|
+
|
31
|
+
def pg_duration(duration)
|
32
|
+
value, unit = duration.integer? ? [duration, 's'] : [(duration * 1000).to_i, 'ms']
|
33
|
+
"#{value}#{unit}"
|
34
|
+
end
|
20
35
|
end
|
21
36
|
end
|
@@ -29,16 +29,27 @@ module SafePgMigrations
|
|
29
29
|
change_column_null create_table add_index remove_index
|
30
30
|
].each do |method|
|
31
31
|
define_method method do |*args, &block|
|
32
|
-
log_blocking_queries { super(*args, &block) }
|
32
|
+
log_blocking_queries(method) { super(*args, &block) }
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
37
|
|
38
|
-
def
|
38
|
+
def delay_before_logging(method)
|
39
|
+
timeout_delay =
|
40
|
+
if %i[add_index remove_index].include?(method)
|
41
|
+
SafePgMigrations.config.index_lock_timeout
|
42
|
+
else
|
43
|
+
SafePgMigrations.config.safe_timeout
|
44
|
+
end
|
45
|
+
|
46
|
+
timeout_delay - SafePgMigrations.config.blocking_activity_logger_margin
|
47
|
+
end
|
48
|
+
|
49
|
+
def log_blocking_queries(method)
|
39
50
|
blocking_queries_retriever_thread =
|
40
51
|
Thread.new do
|
41
|
-
sleep
|
52
|
+
sleep delay_before_logging(method)
|
42
53
|
SafePgMigrations.alternate_connection.query_values(SELECT_BLOCKING_QUERIES_SQL % raw_connection.backend_pid)
|
43
54
|
end
|
44
55
|
|
@@ -65,6 +76,11 @@ module SafePgMigrations
|
|
65
76
|
)
|
66
77
|
SafePgMigrations.say '', true
|
67
78
|
queries.each { |query| SafePgMigrations.say " #{query}", true }
|
79
|
+
SafePgMigrations.say(
|
80
|
+
'Beware, some of those queries might run in a transaction. In this case the locking query might be '\
|
81
|
+
'located elsewhere in the transaction',
|
82
|
+
true
|
83
|
+
)
|
68
84
|
SafePgMigrations.say '', true
|
69
85
|
end
|
70
86
|
|
@@ -2,14 +2,18 @@
|
|
2
2
|
|
3
3
|
module SafePgMigrations
|
4
4
|
module StatementInsurer
|
5
|
+
PG_11_VERSION_NUM = 110_000
|
6
|
+
|
5
7
|
%i[change_column_null add_foreign_key create_table].each do |method|
|
6
8
|
define_method method do |*args, &block|
|
7
|
-
with_setting(:statement_timeout, SafePgMigrations.config.
|
9
|
+
with_setting(:statement_timeout, SafePgMigrations.config.pg_safe_timeout) { super(*args, &block) }
|
8
10
|
end
|
9
11
|
end
|
10
12
|
|
11
13
|
def add_column(table_name, column_name, type, **options)
|
12
|
-
|
14
|
+
need_default_value_backfill = SafePgMigrations.pg_version_num < PG_11_VERSION_NUM
|
15
|
+
|
16
|
+
default = options.delete(:default) if need_default_value_backfill
|
13
17
|
null = options.delete(:null)
|
14
18
|
|
15
19
|
if !default.nil? || null == false
|
@@ -18,7 +22,7 @@ module SafePgMigrations
|
|
18
22
|
|
19
23
|
super
|
20
24
|
|
21
|
-
|
25
|
+
if need_default_value_backfill && !default.nil?
|
22
26
|
SafePgMigrations.say_method_call(:change_column_default, table_name, column_name, default)
|
23
27
|
change_column_default(table_name, column_name, default)
|
24
28
|
|
@@ -33,20 +37,18 @@ module SafePgMigrations
|
|
33
37
|
end
|
34
38
|
|
35
39
|
def add_index(table_name, column_name, **options)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
without_statement_timeout { super }
|
40
|
+
options[:algorithm] = :concurrently
|
41
|
+
SafePgMigrations.say_method_call(:add_index, table_name, column_name, **options)
|
42
|
+
|
43
|
+
with_index_timeouts { super }
|
41
44
|
end
|
42
45
|
|
43
46
|
def remove_index(table_name, options = {})
|
44
47
|
options = { column: options } unless options.is_a?(Hash)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
without_statement_timeout { super }
|
48
|
+
options[:algorithm] = :concurrently
|
49
|
+
SafePgMigrations.say_method_call(:remove_index, table_name, **options)
|
50
|
+
|
51
|
+
with_index_timeouts { super }
|
50
52
|
end
|
51
53
|
|
52
54
|
def backfill_column_default(table_name, column_name)
|
@@ -86,5 +88,13 @@ module SafePgMigrations
|
|
86
88
|
def without_statement_timeout
|
87
89
|
with_setting(:statement_timeout, 0) { yield }
|
88
90
|
end
|
91
|
+
|
92
|
+
def with_index_timeouts
|
93
|
+
without_statement_timeout do
|
94
|
+
with_setting(:lock_timeout, SafePgMigrations.config.pg_index_lock_timeout) do
|
95
|
+
yield
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
89
99
|
end
|
90
100
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SafePgMigrations
|
4
|
+
class VerboseSqlLogger
|
5
|
+
def setup
|
6
|
+
@activerecord_logger_was = ActiveRecord::Base.logger
|
7
|
+
@verbose_query_logs_was = ActiveRecord::Base.verbose_query_logs
|
8
|
+
@colorize_logging_was = ActiveRecord::LogSubscriber.colorize_logging
|
9
|
+
|
10
|
+
disable_marginalia if defined?(Marginalia)
|
11
|
+
|
12
|
+
stdout_logger = Logger.new($stdout, formatter: ->(_severity, _time, _progname, query) { "#{query}\n" })
|
13
|
+
ActiveRecord::Base.logger = stdout_logger
|
14
|
+
ActiveRecord::LogSubscriber.colorize_logging = colorize_logging?
|
15
|
+
# Do not output caller method, we know it is coming from the migration
|
16
|
+
ActiveRecord::Base.verbose_query_logs = false
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
ActiveRecord::Base.verbose_query_logs = @verbose_query_logs_was
|
22
|
+
ActiveRecord::LogSubscriber.colorize_logging = @colorize_logging_was
|
23
|
+
ActiveRecord::Base.logger = @activerecord_logger_was
|
24
|
+
enable_marginalia if defined?(Marginalia)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def colorize_logging?
|
30
|
+
defined?(Rails) && Rails.env.development?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Marginalia annotations will most likely pollute the output
|
34
|
+
def disable_marginalia
|
35
|
+
@marginalia_components_were = Marginalia::Comment.components
|
36
|
+
Marginalia::Comment.components = []
|
37
|
+
end
|
38
|
+
|
39
|
+
def enable_marginalia
|
40
|
+
Marginalia::Comment.components = @marginalia_components_were
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -4,7 +4,7 @@ require 'safe-pg-migrations/base'
|
|
4
4
|
|
5
5
|
module SafePgMigrations
|
6
6
|
class Railtie < Rails::Railtie
|
7
|
-
initializer '
|
7
|
+
initializer 'safe_pg_migrations.insert_into_active_record' do
|
8
8
|
ActiveSupport.on_load :active_record do
|
9
9
|
ActiveRecord::Migration.prepend(SafePgMigrations::Migration)
|
10
10
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safe-pg-migrations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthieu Prat
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-12-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -166,6 +166,7 @@ files:
|
|
166
166
|
- lib/safe-pg-migrations/plugins/idem_potent_statements.rb
|
167
167
|
- lib/safe-pg-migrations/plugins/statement_insurer.rb
|
168
168
|
- lib/safe-pg-migrations/plugins/statement_retrier.rb
|
169
|
+
- lib/safe-pg-migrations/plugins/verbose_sql_logger.rb
|
169
170
|
- lib/safe-pg-migrations/railtie.rb
|
170
171
|
- lib/safe-pg-migrations/version.rb
|
171
172
|
homepage: https://github.com/doctolib/safe-pg-migrations
|