Class: OnlineMigrations::BackgroundMigrations::Migration

Inherits:
ApplicationRecord
  • Object
show all
Defined in:
lib/online_migrations/background_migrations/migration.rb

Overview

Note:

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 =
[
  :enqueued,    # The migration has been enqueued by the user.
  :running,     # The migration is being performed by a migration executor.
  :paused,      # The migration was paused in the middle of the run by the user.
  :finishing,   # The migration is being manually finishing inline by the user.
  :failed,      # The migration raises an exception when running.
  :succeeded,   # The migration finished without error.
  :cancelled,   # The migration was cancelled by the user.
]

Instance Method Summary collapse

Instance Method Details

#can_be_cancelled?Boolean

Returns:

  • (Boolean)


116
117
118
# File 'lib/online_migrations/background_migrations/migration.rb', line 116

def can_be_cancelled?
  !succeeded? && !cancelled?
end

#can_be_paused?Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/online_migrations/background_migrations/migration.rb', line 112

def can_be_paused?
  enqueued? || running?
end

#cancelled!Object Also known as: cancel

Overwrite enum's generated method to correctly work for composite migrations.



98
99
100
101
102
103
104
105
# File 'lib/online_migrations/background_migrations/migration.rb', line 98

def cancelled!
  return super if !composite?

  transaction do
    super
    children.each { |child| child.cancelled! if !child.succeeded? }
  end
end

#completed?Boolean

Returns:

  • (Boolean)


73
74
75
# File 'lib/online_migrations/background_migrations/migration.rb', line 73

def completed?
  succeeded? || failed?
end

#interval_elapsed?Boolean

Returns whether the interval between previous step run has passed.

Returns:

  • (Boolean)


178
179
180
181
182
183
# File 'lib/online_migrations/background_migrations/migration.rb', line 178

def interval_elapsed?
  last_job = migration_jobs.order(:updated_at).last
  return true if last_job.nil?

  last_job.enqueued? || (last_job.updated_at + batch_pause <= Time.current)
end

#last_jobObject



120
121
122
# File 'lib/online_migrations/background_migrations/migration.rb', line 120

def last_job
  migration_jobs.order(:max_value).last
end

#migration_classObject



159
160
161
# File 'lib/online_migrations/background_migrations/migration.rb', line 159

def migration_class
  BackgroundMigration.named(migration_name)
end

#migration_modelObject



171
172
173
# File 'lib/online_migrations/background_migrations/migration.rb', line 171

def migration_model
  migration_relation.model
end

#migration_name=(class_name) ⇒ Object Also known as: name=



67
68
69
70
# File 'lib/online_migrations/background_migrations/migration.rb', line 67

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

#migration_objectObject



163
164
165
# File 'lib/online_migrations/background_migrations/migration.rb', line 163

def migration_object
  @migration_object ||= migration_class.new(*arguments)
end

#migration_relationObject



167
168
169
# File 'lib/online_migrations/background_migrations/migration.rb', line 167

def migration_relation
  migration_object.relation
end

#pausable?Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/online_migrations/background_migrations/migration.rb', line 108

def pausable?
  true
end

#paused!Object

Overwrite enum's generated method to correctly work for composite migrations.



78
79
80
81
82
83
84
85
# File 'lib/online_migrations/background_migrations/migration.rb', line 78

def paused!
  return super if !composite?

  transaction do
    super
    children.each { |child| child.paused! if child.enqueued? || child.running? }
  end
end

#progressFloat?

Returns the progress of the background migration.

Returns:

  • (Float, nil)
    • when background migration is configured to not track progress, returns nil
    • otherwise returns value in range from 0.0 to 100.0


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/online_migrations/background_migrations/migration.rb', line 130

def progress
  if succeeded?
    100.0
  elsif enqueued?
    0.0
  elsif composite?
    rows_counts = children.to_a.pluck(:rows_count)
    if rows_counts.none?(nil)
      total_rows_count = rows_counts.sum
      return 100.0 if total_rows_count == 0

      progresses = children.map do |child|
        child.progress * child.rows_count / total_rows_count # weighted progress
      end

      progresses.sum.round(2)
    end
  elsif rows_count
    if rows_count > 0 && rows_count > batch_size
      jobs_rows_count = migration_jobs.succeeded.sum(:batch_size)
      # The last migration job may need to process the amount of rows
      # less than the batch size, so we can get a value > 1.0.
      ([jobs_rows_count.to_f / rows_count, 1.0].min * 100).round(2)
    else
      0.0
    end
  end
end

#retryObject Also known as: retry_failed_jobs

Mark this migration as ready to be processed again.

This method marks failed jobs as ready to be processed again, and they will be picked up on the next Scheduler run.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/online_migrations/background_migrations/migration.rb', line 190

def retry
  if composite? && failed?
    transaction do
      update!(status: :enqueued, finished_at: nil)
      children.failed.each(&:retry)
    end

    true
  elsif failed?
    transaction do
      parent.update!(status: :enqueued, finished_at: nil) if parent
      update!(status: :enqueued, started_at: nil, finished_at: nil)

      iterator = BatchIterator.new(migration_jobs.failed)
      iterator.each_batch(of: 100) do |batch|
        batch.each(&:retry)
      end
    end

    true
  else
    false
  end
end

#running!Object

Overwrite enum's generated method to correctly work for composite migrations.



88
89
90
91
92
93
94
95
# File 'lib/online_migrations/background_migrations/migration.rb', line 88

def running!
  return super if !composite?

  transaction do
    super
    children.each { |child| child.running! if child.paused? }
  end
end