Skip to content

Execute ActiveRecord migrations with Percona's pt-online-schema-change.

License

Notifications You must be signed in to change notification settings

gumroad/alterity

Repository files navigation

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

  1. You need to have pt-online-schema-change installed wherever you intend on running the migrations.

  2. Add the gem to your Gemfile and bundle 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.