Class: OnlineMigrations::BackgroundDataMigrations::Migration
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- OnlineMigrations::BackgroundDataMigrations::Migration
- Includes:
- ShardAware
- Defined in:
- lib/online_migrations/background_data_migrations/migration.rb
Overview
The records of this class should not be created manually, but via ‘enqueue_background_data_migration` helper inside migrations.
Class representing background data migration.
Constant Summary collapse
- STATUSES =
[ "pending", # The migration has been created by the user. "enqueued", # The migration has been enqueued by the scheduler. "running", # The migration is being performed by a migration executor. "pausing", # The migration has been told to pause but is finishing work. "paused", # The migration was paused in the middle of the run by the user. "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. "cancelling", # The migration has been told to cancel but is finishing work. "cancelled", # The migration was cancelled by the user. "delayed", # The migration was created, but waiting approval from the user to start running. ]
- COMPLETED_STATUSES =
["succeeded", "failed", "cancelled"]
- ACTIVE_STATUSES =
[ "pending", "enqueued", "running", "failed", "pausing", "paused", "cancelling", ]
- STOPPING_STATUSES =
["pausing", "cancelling", "cancelled"]
Class Method Summary collapse
Instance Method Summary collapse
-
#active? ⇒ Boolean
Returns whether the migration is active, which is defined as having a status of pending, enqueued, running, pausing, paused, or cancelling.
-
#cancel ⇒ Boolean
Cancel this data migration.
- #complete ⇒ Object
-
#completed? ⇒ Boolean
Returns whether the migration is completed, which is defined as having a status of succeeded, failed, or cancelled.
-
#data_migration ⇒ OnlineMigrations::DataMigration
Returns data migration associated with this migration.
-
#enqueue ⇒ Boolean
Enqueue this data migration.
- #migration_name=(class_name) ⇒ Object (also: #name=)
-
#pausable? ⇒ Boolean
Returns whether this migration is pausable.
-
#pause ⇒ Boolean
Pause this data migration.
- #persist_error(error, attempt) ⇒ Object
- #persist_progress(cursor, number_of_ticks, duration) ⇒ Object
-
#progress ⇒ Float?
Returns the progress of the data migration.
-
#resume ⇒ Boolean
Resume this data migration.
-
#retry ⇒ Object
Mark this migration as ready to be processed again.
- #start ⇒ Object
-
#started? ⇒ Boolean
Returns whether the migration has been started, which is indicated by the started_at timestamp being present.
- #stop ⇒ Object
-
#stopping? ⇒ Boolean
Returns whether the migration is stopping, which is defined as having a status of pausing or cancelling.
-
#stuck? ⇒ Boolean
Returns whether a migration is stuck, which is defined as having a status of running, cancelling or pausing, and not having been updated in the last 5 minutes.
Methods included from ShardAware
#connection_class, #connection_class_name=, #on_shard_if_present
Class Method Details
.normalize_migration_name(migration_name) ⇒ Object
64 65 66 67 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 64 def self.normalize_migration_name(migration_name) namespace = ::OnlineMigrations.config.background_data_migrations.migrations_module migration_name.sub(/^(::)?#{namespace}::/, "") end |
Instance Method Details
#active? ⇒ Boolean
Returns whether the migration is active, which is defined as having a status of pending, enqueued, running, pausing, paused, or cancelling.
98 99 100 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 98 def active? ACTIVE_STATUSES.include?(status) end |
#cancel ⇒ Boolean
Cancel this data migration. No-op if migration is completed.
151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 151 def cancel return false if completed? if paused? || delayed? || stuck? update!(status: :cancelled, finished_at: Time.current) elsif pending? || enqueued? || errored? cancelled! else cancelling! end true end |
#complete ⇒ Object
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 212 def complete return false if completed? if running? update!(status: :succeeded, finished_at: Time.current) data_migration.after_complete elsif pausing? update!(status: :paused, finished_at: Time.current) elsif cancelling? update!(status: :cancelled, finished_at: Time.current) data_migration.after_complete end true end |
#completed? ⇒ Boolean
Returns whether the migration is completed, which is defined as having a status of succeeded, failed, or cancelled.
89 90 91 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 89 def completed? COMPLETED_STATUSES.include?(status) end |
#data_migration ⇒ OnlineMigrations::DataMigration
Returns data migration associated with this migration.
279 280 281 282 283 284 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 279 def data_migration @data_migration ||= begin klass = DataMigration.named(migration_name) klass.new(*arguments) end end |
#enqueue ⇒ Boolean
Enqueue this data migration. No-op if migration is not delayed.
138 139 140 141 142 143 144 145 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 138 def enqueue if delayed? pending! true else false end end |
#migration_name=(class_name) ⇒ Object Also known as: name=
69 70 71 72 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 69 def migration_name=(class_name) class_name = class_name.name if class_name.is_a?(Class) write_attribute(:migration_name, self.class.normalize_migration_name(class_name)) end |
#pausable? ⇒ Boolean
Returns whether this migration is pausable.
255 256 257 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 255 def pausable? true end |
#pause ⇒ Boolean
Pause this data migration. No-op if migration is completed.
169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 169 def pause return false if completed? if pending? || enqueued? || delayed? || stuck? || errored? paused! else pausing! end true end |
#persist_error(error, attempt) ⇒ Object
238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 238 def persist_error(error, attempt) backtrace = error.backtrace backtrace_cleaner = OnlineMigrations.config.backtrace_cleaner backtrace = backtrace_cleaner.clean(backtrace) if backtrace_cleaner status = attempt >= max_attempts ? :failed : :errored update!( status: status, finished_at: Time.current, error_class: error.class.name, error_message: error., backtrace: backtrace ) end |
#persist_progress(cursor, number_of_ticks, duration) ⇒ Object
229 230 231 232 233 234 235 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 229 def persist_progress(cursor, number_of_ticks, duration) update!( cursor: cursor, tick_count: tick_count + number_of_ticks, time_running: time_running + duration ) end |
#progress ⇒ Float?
Returns the progress of the data migration.
265 266 267 268 269 270 271 272 273 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 265 def progress if succeeded? 100.0 elsif tick_total == 0 0.0 elsif tick_total ([tick_count.to_f / tick_total, 1.0].min * 100) end end |
#resume ⇒ Boolean
Resume this data migration. No-op if migration is not paused.
185 186 187 188 189 190 191 192 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 185 def resume if paused? pending! true else false end end |
#retry ⇒ Object
Mark this migration as ready to be processed again.
This method marks failed migrations as ready to be processed again, and they will be picked up on the next Scheduler run.
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 291 def retry if failed? update!( status: :pending, started_at: nil, finished_at: nil, error_class: nil, error_message: nil, backtrace: nil, jid: nil ) true else false end end |
#start ⇒ Object
124 125 126 127 128 129 130 131 132 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 124 def start if enqueued? update!(status: :running, started_at: Time.current) data_migration.after_start true else false end end |
#started? ⇒ Boolean
Returns whether the migration has been started, which is indicated by the started_at timestamp being present.
80 81 82 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 80 def started? started_at.present? end |
#stop ⇒ Object
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 195 def stop return false if completed? if cancelling? update!(status: :cancelled, finished_at: Time.current) data_migration.after_cancel data_migration.after_complete elsif pausing? paused! data_migration.after_pause end data_migration.after_stop true end |
#stopping? ⇒ Boolean
Returns whether the migration is stopping, which is defined as having a status of pausing or cancelling. The status of cancelled is also considered stopping since a migration can be cancelled while its job still exists in the queue, and we want to handle it the same way as a cancelling run.
109 110 111 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 109 def stopping? STOPPING_STATUSES.include?(status) end |
#stuck? ⇒ Boolean
Returns whether a migration is stuck, which is defined as having a status of running, cancelling or pausing, and not having been updated in the last 5 minutes.
118 119 120 121 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 118 def stuck? stuck_timeout = OnlineMigrations.config.background_data_migrations.stuck_timeout (running? || cancelling? || pausing?) && updated_at <= stuck_timeout.ago end |