Class: OnlineMigrations::BackgroundSchemaMigrations::Migration

Inherits:
ApplicationRecord
  • Object
show all
Includes:
ShardAware
Defined in:
lib/online_migrations/background_schema_migrations/migration.rb

Overview

Note:

The records of this class should not be created manually, but via ‘enqueue_background_schema_migration` helper inside migrations.

Class representing background schema migration.

Constant Summary collapse

STATUSES =
[
  "pending",     # The migration has been created by the user.
  "running",     # The migration is being performed by a migration executor.
  "errored",     # The migration raised an error during last run.
  "failed",      # The migration raises an error when running and retry attempts exceeded.
  "succeeded",   # The migration finished without error.
  "cancelled",   # The migration was cancelled by the user.
  "delayed",     # The migration was created, but waiting approval from the user to start running.
]
MAX_IDENTIFIER_LENGTH =
63

Instance Method Summary collapse

Methods included from ShardAware

#connection_class, #connection_class_name=, #on_shard_if_present

Instance Method Details

#active?Boolean

Returns whether the migration is active, which is defined as having a status of pending, or running.

Returns:

  • (Boolean)

    whether the migration is active.



66
67
68
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 66

def active?
  pending? || running?
end

#attempts_exceeded?Boolean

Returns:

  • (Boolean)


147
148
149
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 147

def attempts_exceeded?
  attempts >= max_attempts
end

#cancelBoolean

Cancel this schema migration. No-op if migration is completed.

Returns:

  • (Boolean)

    whether this schema migration was cancelled.



133
134
135
136
137
138
139
140
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 133

def cancel
  if completed?
    false
  elsif pending? || errored? || delayed? || stuck?
    cancelled!
    true
  end
end

#completed?Boolean

Returns whether the migration is completed, which is defined as having a status of succeeded, failed, or cancelled.

Returns:

  • (Boolean)

    whether the migration is completed.



57
58
59
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 57

def completed?
  succeeded? || failed? || cancelled?
end

#enqueueBoolean

Enqueue this data migration. No-op if migration is not delayed.

Returns:

  • (Boolean)

    whether this data migration was enqueued.



120
121
122
123
124
125
126
127
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 120

def enqueue
  if delayed?
    pending!
    true
  else
    false
  end
end

#index_addition?Boolean

Returns:

  • (Boolean)


142
143
144
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 142

def index_addition?
  definition.match?(/create (unique )?index/i)
end

#pausable?Boolean

Returns whether this migration is pausable.

Returns:

  • (Boolean)


72
73
74
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 72

def pausable?
  false
end

#progressnil

Dummy method to support the same interface as background data migrations.

Returns:

  • (nil)


80
81
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 80

def progress
end

#retryObject

Mark this migration as ready to be processed again.

This is used to manually retrying failed migrations.



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 98

def retry
  if failed?
    update!(
      status: :pending,
      attempts: 0,
      started_at: nil,
      finished_at: nil,
      error_class: nil,
      error_message: nil,
      backtrace: nil
    )

    true
  else
    false
  end
end

#runObject



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 152

def run
  on_shard_if_present do
    with_connection do |connection|
      connection.with_lock_retries do
        statement_timeout = self.statement_timeout || OnlineMigrations.config.statement_timeout

        with_statement_timeout(connection, statement_timeout) do
          if index_addition?
            index = connection.indexes(table_name).find { |i| name.match?(/\b#{i.name}\b/) }
            if index
              if index.valid?
                return
              else
                connection.remove_index(table_name, name: index.name, algorithm: :concurrently)
              end
            end
          end

          connection.execute(definition)

          # Outdated statistics + a new index can hurt performance of existing queries.
          if OnlineMigrations.config.auto_analyze
            connection.execute("ANALYZE #{table_name}")
          end
        end
      end
    end
  end
end

#stuck?Boolean

Whether the migration is considered stuck (is running for some configured time).

Returns:

  • (Boolean)


85
86
87
88
89
90
91
92
# File 'lib/online_migrations/background_schema_migrations/migration.rb', line 85

def stuck?
  if index_addition?
    running? && !index_build_in_progress?
  else
    stuck_timeout = (statement_timeout || 1.day) + 10.minutes
    running? && updated_at <= stuck_timeout.seconds.ago
  end
end