Migration Timeouts

Migration Timeouts is a Ruby gem that adds timeouts, explicitly or implicitly, to ActiveRecord migrations.

A lock_timeout sets a timeout on how long PostgreSQL will wait to acquire a lock on tables being altered before failing and rolling back. This prevents lock contention, and long-running migrations.

A statement_timeout sets timeout on how long a single DB statement can run. If a badly constructed migration tries to lock a table for too long, this will fail the migration and trigger a rollback.

This gem provides config options for app-wide settings, and class methods for specifying or disabling timeouts for a single migration.

Migration Timeouts currently only supports PostgreSQL

Installation

Add this line to your application's Gemfile:

gem 'migration_timeouts'

Usage

Configure the default lock timeout in a Rails initializer

#config/initializers/migration_timeouts.rb

MigrationTimeouts.configure do |config|
  config.default_lock_timeout = 3.seconds
  config.default_statement_timeout = 5.seconds
end

And that's all! Now every up migration will execute

SET LOCAL statement_timeout = 5000;
SET LOCAL lock_timeout = 3000;

inside the migration transaction before your migration code runs. No lock timeout will be used for the down migration.

Disabling

If you set app-wide timeout settings, you can disable them for single migrations.

Here are the available helper methods:

  class AddFoo < ActiveRecord::Migration

    disable_lock_timeout!
    disable_statement_timeout!
    disable_timeouts!

    def change
      create_table :foo do |t|
        t.timestamps
      end
    end
  end

Custom lock timeout

You can change the duration of the timeouts by using:

  class AddBar < ActiveRecord::Migration

    lock_timeout 10.seconds
    statement_timeout 15.seconds

    def change
      create_table :bar do |t|
        t.timestamps
      end
    end
  end

Additionally, if you have not set app-wide timeouts, you can use this to set a timeout for a particular migration.

disable_ddl_transaction!

If you use disable_ddl_transaction!, no timeouts will occur

  class AddMonkey < ActiveRecord::Migration

    disable_ddl_transaction!

    def change
      create_table :monkey do |t|
        t.timestamps
      end
    end
  end

Thanks and alternatives

Originally forked from https://github.com/procore/migration-lock-timeout :heart: