Alterity
Alterity is a small utility that allows Rails app to run MySQL table alterations via Percona Toolkit's pt-online-schema-change
while running migrations.
Usage
By default, after adding the gem to the Gemfile, there's nothing to do to use it.
You can run your normal migrations via rails db:migrate
, and where a table would have been ALTERed directly, pt-online-schema-change
is invoked instead.
Example, running a migration with add_column :users, :full_name, :string
would normally execute ALTER TABLE users ADD COLUMN full_name VARCHAR(255)
.
With Alterity, the following will be executed instead: pt-online-schema-change [config] D=[database],t=users --alter "ADD COLUMN full_name VARCHAR(255)"
.
How does it work internally?
Alterity is designed for stability, simplicity and flexibility.
Other gems, like Departure, are reliant on many private internal Rails methods. This creates a recurrent issue where the gem would break migrations every time one of those Rails methods changed behavior or signature, which can happen with any Rails update.
Only when running a migration, Alterity hooks into one stable, public method of the mysql2
gem, where all SQL queries end up.
If the query that's about to be sent to the MySQL server is detected to be a table alteration (ALTER TABLE
, CREATE INDEX
, ...), it's sent to be run via pt-online-schema-change
instead.
That's it.
Installation
-
You need to have
pt-online-schema-change
installed wherever you intend on running the migrations. -
Add the gem to your
Gemfile
andbundle install
:
gem "alterity"
Optional configuration
1- You can configure the behavior in a config/initializers/alterity.rb
file.
Alterity.configure do |config|
# You can fully customize the command that's will be executed, for example:
config.command = -> (altered_table, alter_argument) {
<<~SHELL.squish
pt-online-schema-change
-h #{config.host}
-P #{config.port}
-u #{config.username}
--password=#{config.password}
--alter-foreign-keys-method=auto
--nocheck-replication-filters
--critical-load Threads_running=1000
--max-load Threads_running=200
--set-vars lock_wait_timeout=1
--recursion-method 'dsn=D=#{config.replicas_dsns_database},t=#{config.replicas_dsns_table}'
--execute
--no-check-alter
D=#{config.database},t=#{altered_table}
--alter #{alter_argument}
SHELL
}
# Check out lib/alterity/default_configuration.rb to see the default command used.
# This option, deactivated by default, will set up a database & table
# and fill them with the listed DSNs before running migrations.
# This is useful for PT-OSC (parameter `--recursion-method`) to monitor
# the replica lag while copying rows.
# This table will be truncated and re-filled every time you run migrations.
# See the method `prepare_replicas_dsns_table` in lib/alterity/alterity.rb for details.
config.replicas(
database: "percona",
table: "replicas_dsns",
dsns: [
"h=#{ENV["DB_REPLICA1_HOST"]}",
"h=#{ENV["DB_REPLICA2_HOST"]}",
]
)
# You can set callbacks that run before, during and after a PT-OSC run.
# Useful if you need to have details of the migration logged somewhere specific.
# Examples:
config.before_command = ->(command) { Slack.send_message("#migrations", "Will execute: #{command}") }
config.on_command_output = ->(line) { Slack.send_message("#migrations", line) }
config.after_command = ->(exit_status) { Slack.send_message("#migrations", "Command exited with status: #{exit_status}") }
end
2- You can disable Alterity for a block:
Alterity.disable do
add_column :users, :full_name, :string
end
3- You can disable Alterity altogether by setting the environment variable DISABLE_ALTERITY=1
.
Requirements / Dependencies
- Ruby >= 2.7
- Gem: Rails >= 6.1 (to be able to get the main database config via ActiveRecord, and enhance the migration Rake tasks via Railtie)
- Gem:
mysql2
>= 0.3
License
Copyright (c) 2021 Christophe Maximin. This software is released under the MIT License.