online_migrations 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/README.md +34 -31
  4. data/docs/background_migrations.md +36 -4
  5. data/docs/configuring.md +3 -2
  6. data/lib/generators/online_migrations/install_generator.rb +3 -7
  7. data/lib/generators/online_migrations/templates/add_sharding_to_online_migrations.rb.tt +18 -0
  8. data/lib/generators/online_migrations/templates/initializer.rb.tt +5 -3
  9. data/lib/generators/online_migrations/templates/migration.rb.tt +8 -3
  10. data/lib/generators/online_migrations/upgrade_generator.rb +33 -0
  11. data/lib/online_migrations/background_migrations/application_record.rb +13 -0
  12. data/lib/online_migrations/background_migrations/backfill_column.rb +1 -1
  13. data/lib/online_migrations/background_migrations/copy_column.rb +6 -20
  14. data/lib/online_migrations/background_migrations/delete_orphaned_records.rb +2 -20
  15. data/lib/online_migrations/background_migrations/migration.rb +123 -34
  16. data/lib/online_migrations/background_migrations/migration_helpers.rb +0 -4
  17. data/lib/online_migrations/background_migrations/migration_job.rb +15 -12
  18. data/lib/online_migrations/background_migrations/migration_job_runner.rb +2 -2
  19. data/lib/online_migrations/background_migrations/migration_runner.rb +56 -11
  20. data/lib/online_migrations/background_migrations/reset_counters.rb +3 -9
  21. data/lib/online_migrations/background_migrations/scheduler.rb +5 -15
  22. data/lib/online_migrations/change_column_type_helpers.rb +68 -83
  23. data/lib/online_migrations/command_checker.rb +11 -29
  24. data/lib/online_migrations/config.rb +7 -15
  25. data/lib/online_migrations/copy_trigger.rb +15 -10
  26. data/lib/online_migrations/error_messages.rb +13 -25
  27. data/lib/online_migrations/foreign_keys_collector.rb +2 -2
  28. data/lib/online_migrations/indexes_collector.rb +3 -3
  29. data/lib/online_migrations/lock_retrier.rb +4 -9
  30. data/lib/online_migrations/schema_cache.rb +0 -6
  31. data/lib/online_migrations/schema_dumper.rb +1 -1
  32. data/lib/online_migrations/schema_statements.rb +64 -256
  33. data/lib/online_migrations/utils.rb +18 -56
  34. data/lib/online_migrations/verbose_sql_logs.rb +3 -2
  35. data/lib/online_migrations/version.rb +1 -1
  36. data/lib/online_migrations.rb +7 -6
  37. metadata +8 -7
  38. data/lib/online_migrations/background_migrations/advisory_lock.rb +0 -62
  39. data/lib/online_migrations/foreign_key_definition.rb +0 -17
@@ -2,7 +2,7 @@
2
2
 
3
3
  module OnlineMigrations
4
4
  module BackgroundMigrations
5
- class Migration < ActiveRecord::Base
5
+ class Migration < ApplicationRecord
6
6
  STATUSES = [
7
7
  :enqueued, # The migration has been enqueued by the user.
8
8
  :running, # The migration is being performed by a migration executor.
@@ -15,25 +15,29 @@ module OnlineMigrations
15
15
  self.table_name = :background_migrations
16
16
 
17
17
  scope :queue_order, -> { order(created_at: :asc) }
18
+ scope :runnable, -> { where(composite: false) }
18
19
  scope :active, -> { where(status: [statuses[:enqueued], statuses[:running]]) }
20
+ scope :except_succeeded, -> { where.not(status: :succeeded) }
19
21
  scope :for_migration_name, ->(migration_name) { where(migration_name: normalize_migration_name(migration_name)) }
20
22
  scope :for_configuration, ->(migration_name, arguments) do
21
23
  for_migration_name(migration_name).where("arguments = ?", arguments.to_json)
22
24
  end
23
25
 
24
- enum status: STATUSES.map { |status| [status, status.to_s] }.to_h
26
+ enum status: STATUSES.index_with(&:to_s)
25
27
 
28
+ belongs_to :parent, class_name: name, optional: true
29
+ has_many :children, class_name: name, foreign_key: :parent_id
26
30
  has_many :migration_jobs
27
31
 
28
32
  validates :migration_name, :batch_column_name, presence: true
29
33
 
30
- validates :min_value, :max_value, :batch_size, :sub_batch_size,
31
- presence: true, numericality: { greater_than: 0 }
34
+ validates :batch_size, :sub_batch_size, presence: true, numericality: { greater_than: 0 }
35
+ validates :min_value, :max_value, presence: true, numericality: { greater_than: 0, unless: :composite? }
32
36
 
33
37
  validates :batch_pause, :sub_batch_pause_ms, presence: true,
34
38
  numericality: { greater_than_or_equal_to: 0 }
35
- validates :rows_count, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
36
- validates :arguments, uniqueness: { scope: :migration_name }
39
+ validates :rows_count, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true, unless: :composite?
40
+ validates :arguments, uniqueness: { scope: [:migration_name, :shard] }
37
41
 
38
42
  validate :validate_batch_column_values
39
43
  validate :validate_batch_sizes
@@ -43,6 +47,8 @@ module OnlineMigrations
43
47
  validates_with MigrationStatusValidator, on: :update
44
48
 
45
49
  before_validation :set_defaults
50
+ before_create :create_child_migrations, if: :composite?
51
+ before_update :copy_attributes_to_children, if: :composite?
46
52
 
47
53
  # @private
48
54
  def self.normalize_migration_name(migration_name)
@@ -58,28 +64,53 @@ module OnlineMigrations
58
64
  succeeded? || failed?
59
65
  end
60
66
 
67
+ # Overwrite enum's generated method to correctly work for composite migrations.
68
+ def paused!
69
+ return super if !composite?
70
+
71
+ transaction do
72
+ super
73
+ children.each { |child| child.paused! if child.enqueued? || child.running? }
74
+ end
75
+ end
76
+
77
+ # Overwrite enum's generated method to correctly work for composite migrations.
78
+ def running!
79
+ return super if !composite?
80
+
81
+ transaction do
82
+ super
83
+ children.each { |child| child.running! if child.paused? }
84
+ end
85
+ end
86
+
61
87
  def last_job
62
- migration_jobs.order(max_value: :desc).first
88
+ migration_jobs.order(:max_value).last
63
89
  end
64
90
 
65
91
  def last_completed_job
66
- migration_jobs.completed.order(finished_at: :desc).first
92
+ migration_jobs.completed.order(:finished_at).last
67
93
  end
68
94
 
69
95
  # Returns the progress of the background migration.
70
96
  #
71
97
  # @return [Float, nil]
72
- # - when background migration is configured to not to track progress, returns `nil`
73
- # - otherwise returns value in range of 0.0 and 1.0
98
+ # - when background migration is configured to not track progress, returns `nil`
99
+ # - otherwise returns value in range from 0.0 to 100.0
74
100
  #
75
101
  def progress
76
102
  if succeeded?
77
- 1.0
103
+ 100.0
104
+ elsif composite?
105
+ progresses = children.map(&:progress).compact
106
+ if progresses.any?
107
+ (progresses.sum / progresses.size).round(2)
108
+ end
78
109
  elsif rows_count
79
110
  jobs_rows_count = migration_jobs.succeeded.sum(:batch_size)
80
111
  # The last migration job may need to process the amount of rows
81
112
  # less than the batch size, so we can get a value > 1.0.
82
- [jobs_rows_count.to_f / rows_count, 1.0].min
113
+ ([jobs_rows_count.to_f / rows_count, 1.0].min * 100).round(2)
83
114
  end
84
115
  end
85
116
 
@@ -95,13 +126,19 @@ module OnlineMigrations
95
126
  migration_object.relation
96
127
  end
97
128
 
129
+ def migration_model
130
+ migration_relation.model
131
+ end
132
+
98
133
  # Returns whether the interval between previous step run has passed.
99
134
  # @return [Boolean]
100
135
  #
101
136
  def interval_elapsed?
102
- if migration_jobs.running.exists?
137
+ last_active_job = migration_jobs.active.order(:updated_at).last
138
+
139
+ if last_active_job && !last_active_job.stuck?
103
140
  false
104
- elsif (job = last_completed_job)
141
+ elsif batch_pause > 0 && (job = last_completed_job)
105
142
  job.finished_at + batch_pause <= Time.current
106
143
  else
107
144
  true
@@ -123,6 +160,14 @@ module OnlineMigrations
123
160
  end
124
161
  end
125
162
 
163
+ # @private
164
+ def on_shard(&block)
165
+ abstract_class = find_abstract_class(migration_model)
166
+
167
+ shard = (self.shard || abstract_class.default_shard).to_sym
168
+ abstract_class.connected_to(shard: shard, role: :writing, &block)
169
+ end
170
+
126
171
  # @private
127
172
  def reset_failed_jobs_attempts
128
173
  iterator = BatchIterator.new(migration_jobs.failed.attempts_exceeded)
@@ -138,16 +183,10 @@ module OnlineMigrations
138
183
 
139
184
  # rubocop:disable Lint/UnreachableLoop
140
185
  iterator.each_batch(of: batch_size, column: batch_column_name, start: next_min_value) do |relation|
141
- if Utils.ar_version <= 4.2
142
- # Active Record <= 4.2 does not support pluck with Arel nodes
143
- quoted_column = self.class.connection.quote_column_name(batch_column_name)
144
- batch_range = relation.pluck("MIN(#{quoted_column}), MAX(#{quoted_column})").first
145
- else
146
- min = relation.arel_table[batch_column_name].minimum
147
- max = relation.arel_table[batch_column_name].maximum
186
+ min = relation.arel_table[batch_column_name].minimum
187
+ max = relation.arel_table[batch_column_name].maximum
188
+ batch_range = relation.pick(min, max)
148
189
 
149
- batch_range = relation.pluck(min, max).first
150
- end
151
190
  break
152
191
  end
153
192
  # rubocop:enable Lint/UnreachableLoop
@@ -162,6 +201,10 @@ module OnlineMigrations
162
201
  [min_value, max_value]
163
202
  end
164
203
 
204
+ protected
205
+ attr_accessor :child
206
+ alias child? child
207
+
165
208
  private
166
209
  def validate_batch_column_values
167
210
  if max_value.to_i < min_value.to_i
@@ -176,7 +219,13 @@ module OnlineMigrations
176
219
  end
177
220
 
178
221
  def validate_jobs_status
179
- if succeeded? && migration_jobs.except_succeeded.exists?
222
+ if composite?
223
+ if succeeded? && children.except_succeeded.exists?
224
+ errors.add(:base, "all child migrations must be succeeded")
225
+ elsif failed? && !children.failed.exists?
226
+ errors.add(:base, "at least one child migration must be failed")
227
+ end
228
+ elsif succeeded? && migration_jobs.except_succeeded.exists?
180
229
  errors.add(:base, "all migration jobs must be succeeded")
181
230
  elsif failed? && !migration_jobs.failed.exists?
182
231
  errors.add(:base, "at least one migration job must be failed")
@@ -185,12 +234,30 @@ module OnlineMigrations
185
234
 
186
235
  def set_defaults
187
236
  if migration_relation.is_a?(ActiveRecord::Relation)
188
- self.batch_column_name ||= migration_relation.primary_key
189
- self.min_value ||= migration_relation.minimum(batch_column_name)
190
- self.max_value ||= migration_relation.maximum(batch_column_name)
191
-
192
- count = migration_object.count
193
- self.rows_count = count if count != :no_count
237
+ if !child?
238
+ shards = Utils.shard_names(migration_model)
239
+ self.composite = shards.size > 1
240
+ end
241
+
242
+ self.batch_column_name ||= migration_relation.primary_key
243
+
244
+ if composite?
245
+ self.min_value = self.max_value = self.rows_count = -1 # not relevant
246
+ else
247
+ on_shard do
248
+ self.min_value ||= migration_relation.minimum(batch_column_name)
249
+ self.max_value ||= migration_relation.maximum(batch_column_name)
250
+
251
+ # This can be the case when run in development on empty tables
252
+ if min_value.nil?
253
+ # integer IDs minimum value is 1
254
+ self.min_value = self.max_value = 1
255
+ end
256
+
257
+ count = migration_object.count
258
+ self.rows_count = count if count != :no_count
259
+ end
260
+ end
194
261
  end
195
262
 
196
263
  config = ::OnlineMigrations.config.background_migrations
@@ -199,12 +266,27 @@ module OnlineMigrations
199
266
  self.batch_pause ||= config.batch_pause
200
267
  self.sub_batch_pause_ms ||= config.sub_batch_pause_ms
201
268
  self.batch_max_attempts ||= config.batch_max_attempts
269
+ end
270
+
271
+ def create_child_migrations
272
+ shards = Utils.shard_names(migration_model)
202
273
 
203
- # This can be the case when run in development on empty tables
204
- if min_value.nil?
205
- # integer IDs minimum value is 1
206
- self.min_value = self.max_value = 1
274
+ children = shards.map do |shard|
275
+ child = Migration.new(migration_name: migration_name, arguments: arguments, shard: shard)
276
+ child.child = true
277
+ child
207
278
  end
279
+
280
+ self.children = children
281
+ end
282
+
283
+ def copy_attributes_to_children
284
+ attributes = [:batch_size, :sub_batch_size, :batch_pause, :sub_batch_pause_ms, :batch_max_attempts]
285
+ updates = {}
286
+ attributes.each do |attribute|
287
+ updates[attribute] = read_attribute(attribute) if attribute_changed?(attribute)
288
+ end
289
+ children.update_all(updates) if updates.any?
208
290
  end
209
291
 
210
292
  def next_min_value
@@ -214,6 +296,13 @@ module OnlineMigrations
214
296
  min_value
215
297
  end
216
298
  end
299
+
300
+ def find_abstract_class(model)
301
+ model.ancestors.find do |parent|
302
+ parent == ActiveRecord::Base ||
303
+ (parent.is_a?(Class) && parent.abstract_class?)
304
+ end
305
+ end
217
306
  end
218
307
  end
219
308
  end
@@ -223,10 +223,6 @@ module OnlineMigrations
223
223
  # For smaller tables it is probably better and easier to directly find and delete orpahed records.
224
224
  #
225
225
  def delete_orphaned_records_in_background(model_name, *associations, **options)
226
- if Utils.ar_version <= 4.2
227
- raise "#{__method__} does not support Active Record <= 4.2 yet"
228
- end
229
-
230
226
  model_name = model_name.name if model_name.is_a?(Class)
231
227
 
232
228
  enqueue_background_migration(
@@ -2,7 +2,7 @@
2
2
 
3
3
  module OnlineMigrations
4
4
  module BackgroundMigrations
5
- class MigrationJob < ActiveRecord::Base
5
+ class MigrationJob < ApplicationRecord
6
6
  STATUSES = [
7
7
  :enqueued,
8
8
  :running,
@@ -12,12 +12,11 @@ module OnlineMigrations
12
12
 
13
13
  self.table_name = :background_migration_jobs
14
14
 
15
- # For Active Record <= 4.2 needs to fully specify enum values
16
- scope :active, -> { where(status: [statuses[:enqueued], statuses[:running]]) }
17
- scope :completed, -> { where(status: [statuses[:failed], statuses[:succeeded]]) }
15
+ scope :active, -> { where(status: [:enqueued, :running]) }
16
+ scope :completed, -> { where(status: [:failed, :succeeded]) }
18
17
  scope :stuck, -> do
19
- timeout = ::OnlineMigrations.config.background_migrations.stuck_jobs_timeout
20
- active.where("updated_at <= ?", timeout.ago)
18
+ timeout = OnlineMigrations.config.background_migrations.stuck_jobs_timeout
19
+ active.where("updated_at <= ?", timeout.seconds.ago)
21
20
  end
22
21
 
23
22
  scope :retriable, -> do
@@ -26,7 +25,7 @@ module OnlineMigrations
26
25
  stuck_sql = connection.unprepared_statement { stuck.to_sql }
27
26
  failed_retriable_sql = connection.unprepared_statement { failed_retriable.to_sql }
28
27
 
29
- from(Arel.sql(<<-SQL.strip_heredoc))
28
+ from(Arel.sql(<<~SQL))
30
29
  (
31
30
  (#{failed_retriable_sql})
32
31
  UNION
@@ -35,19 +34,16 @@ module OnlineMigrations
35
34
  SQL
36
35
  end
37
36
 
38
- scope :except_succeeded, -> { where("status != ?", statuses[:succeeded]) }
37
+ scope :except_succeeded, -> { where.not(status: :succeeded) }
39
38
  scope :attempts_exceeded, -> { where("attempts >= max_attempts") }
40
39
 
41
- enum status: STATUSES.map { |status| [status, status.to_s] }.to_h
40
+ enum status: STATUSES.index_with(&:to_s)
42
41
 
43
42
  delegate :migration_class, :migration_object, :migration_relation, :batch_column_name,
44
43
  :arguments, :batch_pause, to: :migration
45
44
 
46
45
  belongs_to :migration
47
46
 
48
- # For Active Record 5.0+ this is validated by default from belongs_to
49
- validates :migration, presence: true
50
-
51
47
  validates :min_value, :max_value, presence: true, numericality: { greater_than: 0 }
52
48
  validate :values_in_migration_range, if: :min_value?
53
49
  validate :validate_values_order, if: :min_value?
@@ -56,6 +52,13 @@ module OnlineMigrations
56
52
 
57
53
  before_create :copy_settings_from_migration
58
54
 
55
+ # Whether the job is considered stuck (is running for some configured time).
56
+ #
57
+ def stuck?
58
+ timeout = OnlineMigrations.config.background_migrations.stuck_jobs_timeout
59
+ running? && updated_at <= timeout.seconds.ago
60
+ end
61
+
59
62
  # Mark this job as ready to be processed again.
60
63
  #
61
64
  # This is used when retrying failed jobs.
@@ -6,7 +6,7 @@ module OnlineMigrations
6
6
  class MigrationJobRunner
7
7
  attr_reader :migration_job
8
8
 
9
- delegate :attempts, :migration_relation, :migration_object, :sub_batch_size,
9
+ delegate :migration, :attempts, :migration_relation, :migration_object, :sub_batch_size,
10
10
  :batch_column_name, :min_value, :max_value, :pause_ms, to: :migration_job
11
11
 
12
12
  def initialize(migration_job)
@@ -30,7 +30,7 @@ module OnlineMigrations
30
30
  )
31
31
 
32
32
  ActiveSupport::Notifications.instrument("process_batch.background_migrations", job_payload) do
33
- run_batch
33
+ migration.on_shard { run_batch }
34
34
  end
35
35
 
36
36
  migration_job.update!(status: :succeeded, finished_at: Time.current)
@@ -12,8 +12,13 @@ module OnlineMigrations
12
12
 
13
13
  # Runs one background migration job.
14
14
  def run_migration_job
15
- migration.running! if migration.enqueued?
16
- migration_payload = { background_migration: migration }
15
+ raise "Should not be called on a composite (with sharding) migration" if migration.composite?
16
+
17
+ if migration.enqueued?
18
+ migration.running!
19
+ migration.parent.running! if migration.parent && migration.parent.enqueued?
20
+ end
21
+ migration_payload = notifications_payload(migration)
17
22
 
18
23
  if !migration.migration_jobs.exists?
19
24
  ActiveSupport::Notifications.instrument("started.background_migrations", migration_payload)
@@ -37,6 +42,8 @@ module OnlineMigrations
37
42
  end
38
43
 
39
44
  ActiveSupport::Notifications.instrument("completed.background_migrations", migration_payload)
45
+
46
+ complete_parent_if_needed(migration) if migration.parent.present?
40
47
  end
41
48
 
42
49
  next_migration_job
@@ -52,8 +59,15 @@ module OnlineMigrations
52
59
 
53
60
  migration.running!
54
61
 
55
- while migration.running?
56
- run_migration_job
62
+ if migration.composite?
63
+ migration.children.each do |child_migration|
64
+ runner = self.class.new(child_migration)
65
+ runner.run_all_migration_jobs
66
+ end
67
+ else
68
+ while migration.running?
69
+ run_migration_job
70
+ end
57
71
  end
58
72
  end
59
73
 
@@ -64,13 +78,20 @@ module OnlineMigrations
64
78
  def finish
65
79
  return if migration.completed?
66
80
 
67
- # Mark is as finishing to avoid being picked up
68
- # by the background migrations scheduler.
69
- migration.finishing!
70
- migration.reset_failed_jobs_attempts
71
-
72
- while migration.finishing?
73
- run_migration_job
81
+ if migration.composite?
82
+ migration.children.each do |child_migration|
83
+ runner = self.class.new(child_migration)
84
+ runner.finish
85
+ end
86
+ else
87
+ # Mark is as finishing to avoid being picked up
88
+ # by the background migrations scheduler.
89
+ migration.finishing!
90
+ migration.reset_failed_jobs_attempts
91
+
92
+ while migration.finishing?
93
+ run_migration_job
94
+ end
74
95
  end
75
96
  end
76
97
 
@@ -95,6 +116,30 @@ module OnlineMigrations
95
116
  max_value: max_value
96
117
  )
97
118
  end
119
+
120
+ def complete_parent_if_needed(migration)
121
+ parent = migration.parent
122
+ completed = false
123
+
124
+ parent.with_lock do
125
+ children = parent.children.select(:status)
126
+ if children.all?(&:succeeded?)
127
+ parent.succeeded!
128
+ completed = true
129
+ elsif children.any?(&:failed?)
130
+ parent.failed!
131
+ completed = true
132
+ end
133
+ end
134
+
135
+ if completed
136
+ ActiveSupport::Notifications.instrument("completed.background_migrations", notifications_payload(migration))
137
+ end
138
+ end
139
+
140
+ def notifications_payload(migration)
141
+ { background_migration: migration }
142
+ end
98
143
  end
99
144
  end
100
145
  end
@@ -26,7 +26,7 @@ module OnlineMigrations
26
26
  counter_name = reflection.counter_cache_column
27
27
 
28
28
  quoted_association_table = connection.quote_table_name(has_many_association.table_name)
29
- count_subquery = <<-SQL.strip_heredoc
29
+ count_subquery = <<~SQL
30
30
  SELECT COUNT(*)
31
31
  FROM #{quoted_association_table}
32
32
  WHERE #{quoted_association_table}.#{connection.quote_column_name(foreign_key)} =
@@ -41,8 +41,7 @@ module OnlineMigrations
41
41
  names = Array.wrap(names)
42
42
  options = names.extract_options!
43
43
  touch_updates = touch_attributes_with_time(*names, **options)
44
- # In Active Record 4.2 sanitize_sql_for_assignment is protected
45
- updates << model.send(:sanitize_sql_for_assignment, touch_updates)
44
+ updates << model.sanitize_sql_for_assignment(touch_updates)
46
45
  end
47
46
 
48
47
  relation.update_all(updates.join(", "))
@@ -64,11 +63,6 @@ module OnlineMigrations
64
63
 
65
64
  has_many_association = has_many.find do |association|
66
65
  counter_cache_column = association.counter_cache_column
67
-
68
- # Active Record <= 4.2 is able to return only explicitly provided `counter_cache` column.
69
- if !counter_cache_column && Utils.ar_version <= 4.2
70
- counter_cache_column = "#{association.name}_count"
71
- end
72
66
  counter_cache_column && counter_cache_column.to_sym == counter_association.to_sym
73
67
  end
74
68
 
@@ -86,7 +80,7 @@ module OnlineMigrations
86
80
  def touch_attributes_with_time(*names, time: nil)
87
81
  attribute_names = timestamp_attributes_for_update & model.column_names
88
82
  attribute_names |= names.map(&:to_s)
89
- attribute_names.map { |attribute_name| [attribute_name, time || Time.current] }.to_h
83
+ attribute_names.index_with(time || Time.current)
90
84
  end
91
85
 
92
86
  def timestamp_attributes_for_update
@@ -4,15 +4,14 @@ module OnlineMigrations
4
4
  module BackgroundMigrations
5
5
  # Class responsible for scheduling background migrations.
6
6
  # It selects runnable background migrations and runs them one step (one batch) at a time.
7
- # A migration is considered runnable if it is not completed and time the interval between
7
+ # A migration is considered runnable if it is not completed and the time interval between
8
8
  # successive runs has passed.
9
- # Scheduler ensures (via advisory locks) that at most one background migration at a time is running per database.
10
9
  #
11
- # Scheduler should be run via some kind of periodical means, for example, cron.
10
+ # Scheduler should be configured to run periodically, for example, via cron.
12
11
  # @example Run via whenever
13
12
  # # add this to schedule.rb
14
13
  # every 1.minute do
15
- # runner "OnlineMigrations::BackgroundMigrations::Scheduler.run"
14
+ # runner "OnlineMigrations.run_background_migrations"
16
15
  # end
17
16
  #
18
17
  class Scheduler
@@ -22,24 +21,15 @@ module OnlineMigrations
22
21
 
23
22
  # Runs Scheduler
24
23
  def run
25
- active_migrations = Migration.active.queue_order
24
+ active_migrations = Migration.runnable.active.queue_order
26
25
  runnable_migrations = active_migrations.select(&:interval_elapsed?)
27
26
 
28
27
  runnable_migrations.each do |migration|
29
- connection = migration.migration_relation.connection
30
-
31
- with_exclusive_lock(connection) do
32
- run_migration_job(migration)
33
- end
28
+ run_migration_job(migration)
34
29
  end
35
30
  end
36
31
 
37
32
  private
38
- def with_exclusive_lock(connection, &block)
39
- lock = AdvisoryLock.new(name: "online_migrations_scheduler", connection: connection)
40
- lock.with_lock(&block)
41
- end
42
-
43
33
  def run_migration_job(migration)
44
34
  runner = MigrationRunner.new(migration)
45
35
  runner.run_migration_job