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.
-
#cursor ⇒ Object
TODO: delete in some future version.
-
#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 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
66 67 68 69 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 66 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.
107 108 109 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 107 def active? ACTIVE_STATUSES.include?(status) end |
#cancel ⇒ Boolean
Cancel this data migration. No-op if migration is completed.
166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 166 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
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 227 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.
98 99 100 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 98 def completed? COMPLETED_STATUSES.include?(status) end |
#cursor ⇒ Object
TODO: delete in some future version
72 73 74 75 76 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 72 def cursor self[:cursor] rescue JSON::ParserError cursor_before_type_cast end |
#data_migration ⇒ OnlineMigrations::DataMigration
Returns data migration associated with this migration.
294 295 296 297 298 299 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 294 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.
153 154 155 156 157 158 159 160 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 153 def enqueue if delayed? pending! true else false end end |
#migration_name=(class_name) ⇒ Object Also known as: name=
78 79 80 81 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 78 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.
270 271 272 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 270 def pausable? true end |
#pause ⇒ Boolean
Pause this data migration. No-op if migration is completed.
184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 184 def pause return false if completed? if pending? || enqueued? || delayed? || stuck? || errored? paused! else pausing! end true end |
#persist_error(error, attempt) ⇒ Object
253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 253 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
244 245 246 247 248 249 250 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 244 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.
280 281 282 283 284 285 286 287 288 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 280 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.
200 201 202 203 204 205 206 207 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 200 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.
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 306 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
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 133 def start if enqueued? # Defer `tick_total` calculation to the migration starting time # instead of the enqueueing time to avoid failed deploys. self.tick_total ||= safely_calculate_tick_total self.status = :running self.started_at = Time.current save! 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.
89 90 91 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 89 def started? started_at.present? end |
#stop ⇒ Object
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 210 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.
118 119 120 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 118 def stopping? STOPPING_STATUSES.include?(status) end |
#stuck? ⇒ Boolean
Returns whether a migration is stuck, which is defined as having a status of cancelling or pausing, and not having been updated in the last 5 minutes.
127 128 129 130 |
# File 'lib/online_migrations/background_data_migrations/migration.rb', line 127 def stuck? stuck_timeout = OnlineMigrations.config.background_data_migrations.stuck_timeout (cancelling? || pausing?) && updated_at <= stuck_timeout.ago end |