online_migrations 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/docs/0.27-upgrade.md +24 -0
- data/docs/background_data_migrations.md +200 -101
- data/docs/background_schema_migrations.md +2 -2
- data/lib/generators/online_migrations/{background_migration_generator.rb → data_migration_generator.rb} +4 -4
- data/lib/generators/online_migrations/templates/change_background_data_migrations.rb.tt +34 -0
- data/lib/generators/online_migrations/templates/{background_data_migration.rb.tt → data_migration.rb.tt} +8 -9
- data/lib/generators/online_migrations/templates/initializer.rb.tt +19 -25
- data/lib/generators/online_migrations/templates/install_migration.rb.tt +9 -40
- data/lib/generators/online_migrations/upgrade_generator.rb +16 -8
- data/lib/online_migrations/active_record_batch_enumerator.rb +8 -0
- data/lib/online_migrations/background_data_migrations/backfill_column.rb +50 -0
- data/lib/online_migrations/background_data_migrations/config.rb +62 -0
- data/lib/online_migrations/{background_migrations → background_data_migrations}/copy_column.rb +15 -28
- data/lib/online_migrations/{background_migrations → background_data_migrations}/delete_associated_records.rb +9 -5
- data/lib/online_migrations/{background_migrations → background_data_migrations}/delete_orphaned_records.rb +5 -9
- data/lib/online_migrations/background_data_migrations/migration.rb +312 -0
- data/lib/online_migrations/{background_migrations → background_data_migrations}/migration_helpers.rb +72 -61
- data/lib/online_migrations/background_data_migrations/migration_job.rb +158 -0
- data/lib/online_migrations/background_data_migrations/migration_status_validator.rb +65 -0
- data/lib/online_migrations/{background_migrations → background_data_migrations}/perform_action_on_relation.rb +5 -5
- data/lib/online_migrations/{background_migrations → background_data_migrations}/reset_counters.rb +5 -5
- data/lib/online_migrations/background_data_migrations/scheduler.rb +78 -0
- data/lib/online_migrations/background_data_migrations/ticker.rb +62 -0
- data/lib/online_migrations/background_schema_migrations/config.rb +2 -2
- data/lib/online_migrations/background_schema_migrations/migration.rb +51 -123
- data/lib/online_migrations/background_schema_migrations/migration_helpers.rb +25 -46
- data/lib/online_migrations/background_schema_migrations/migration_runner.rb +43 -97
- data/lib/online_migrations/background_schema_migrations/scheduler.rb +2 -2
- data/lib/online_migrations/change_column_type_helpers.rb +3 -2
- data/lib/online_migrations/config.rb +4 -4
- data/lib/online_migrations/data_migration.rb +127 -0
- data/lib/online_migrations/lock_retrier.rb +5 -2
- data/lib/online_migrations/schema_statements.rb +1 -1
- data/lib/online_migrations/shard_aware.rb +44 -0
- data/lib/online_migrations/version.rb +1 -1
- data/lib/online_migrations.rb +18 -11
- metadata +22 -21
- data/lib/online_migrations/background_migration.rb +0 -64
- data/lib/online_migrations/background_migrations/backfill_column.rb +0 -54
- data/lib/online_migrations/background_migrations/background_migration_class_validator.rb +0 -29
- data/lib/online_migrations/background_migrations/config.rb +0 -74
- data/lib/online_migrations/background_migrations/migration.rb +0 -329
- data/lib/online_migrations/background_migrations/migration_job.rb +0 -109
- data/lib/online_migrations/background_migrations/migration_job_runner.rb +0 -66
- data/lib/online_migrations/background_migrations/migration_job_status_validator.rb +0 -29
- data/lib/online_migrations/background_migrations/migration_runner.rb +0 -161
- data/lib/online_migrations/background_migrations/migration_status_validator.rb +0 -48
- data/lib/online_migrations/background_migrations/scheduler.rb +0 -42
@@ -78,67 +78,46 @@ module OnlineMigrations
|
|
78
78
|
# ensure_background_schema_migration_succeeded("index_users_on_email")
|
79
79
|
#
|
80
80
|
def ensure_background_schema_migration_succeeded(migration_name)
|
81
|
-
|
81
|
+
migrations = Migration.where(migration_name: migration_name).to_a
|
82
82
|
|
83
|
-
if
|
84
|
-
Utils.raise_in_prod_or_say_in_dev("Could not find background schema migration: '#{migration_name}'")
|
85
|
-
elsif !
|
86
|
-
raise "Expected background schema migration '#{migration_name}' to be marked as 'succeeded'
|
87
|
-
"but it is '#{migration.status}'."
|
83
|
+
if migrations.empty?
|
84
|
+
Utils.raise_in_prod_or_say_in_dev("Could not find background schema migration(s): '#{migration_name}'.")
|
85
|
+
elsif !migrations.all?(&:succeeded?)
|
86
|
+
raise "Expected background schema migration(s) '#{migration_name}' to be marked as 'succeeded'."
|
88
87
|
end
|
89
88
|
end
|
90
89
|
|
91
|
-
def enqueue_background_schema_migration(
|
92
|
-
|
93
|
-
raise ArgumentError, "You must pass a :connection_class_name when using multiple databases."
|
94
|
-
end
|
95
|
-
|
96
|
-
migration = create_background_schema_migration(name, table_name, **options)
|
90
|
+
def enqueue_background_schema_migration(migration_name, table_name, connection_class_name: nil, **options)
|
91
|
+
options.assert_valid_keys(:definition, :max_attempts, :statement_timeout)
|
97
92
|
|
98
|
-
|
99
|
-
|
100
|
-
runner = MigrationRunner.new(migration)
|
101
|
-
runner.run
|
93
|
+
if Utils.multiple_databases? && !connection_class_name
|
94
|
+
raise ArgumentError, "You must pass a :connection_class_name when using multiple databases."
|
102
95
|
end
|
103
96
|
|
104
|
-
migration
|
105
|
-
end
|
106
|
-
|
107
|
-
# @private
|
108
|
-
def create_background_schema_migration(migration_name, table_name, connection_class_name: nil, **options)
|
109
|
-
options.assert_valid_keys(:definition, :max_attempts, :statement_timeout)
|
110
|
-
|
111
97
|
if connection_class_name
|
112
|
-
|
98
|
+
klass = connection_class_name.constantize
|
99
|
+
connection_class = Utils.find_connection_class(klass)
|
100
|
+
# Normalize to the real connection class name.
|
101
|
+
connection_class_name = connection_class.name
|
102
|
+
else
|
103
|
+
connection_class = ActiveRecord::Base
|
113
104
|
end
|
114
105
|
|
115
|
-
|
116
|
-
|
117
|
-
migration.assign_attributes(**options, table_name: table_name)
|
106
|
+
shards = Utils.shard_names(connection_class)
|
107
|
+
shards = [nil] if shards.size == 1
|
118
108
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
child = migration.dup
|
123
|
-
child.shard = shard
|
124
|
-
child
|
125
|
-
end
|
109
|
+
shards.each do |shard|
|
110
|
+
migration = Migration.create_with(**options, table_name: table_name)
|
111
|
+
.find_or_create_by!(migration_name: migration_name, shard: shard, connection_class_name: connection_class_name)
|
126
112
|
|
127
|
-
|
113
|
+
if Utils.run_background_migrations_inline?
|
114
|
+
runner = MigrationRunner.new(migration)
|
115
|
+
runner.run
|
128
116
|
end
|
129
117
|
end
|
130
|
-
end
|
131
118
|
|
132
|
-
|
133
|
-
|
134
|
-
if connection_class_name
|
135
|
-
klass = connection_class_name.safe_constantize
|
136
|
-
if klass
|
137
|
-
connection_class = Utils.find_connection_class(klass)
|
138
|
-
connection_class.name if connection_class
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
119
|
+
true
|
120
|
+
end
|
142
121
|
end
|
143
122
|
end
|
144
123
|
end
|
@@ -13,119 +13,65 @@ module OnlineMigrations
|
|
13
13
|
def run
|
14
14
|
return if migration.cancelled? || migration.succeeded?
|
15
15
|
|
16
|
-
|
16
|
+
migration.running! if migration.enqueued? || migration.errored?
|
17
|
+
migration_payload = { migration: migration }
|
17
18
|
|
18
|
-
if migration.
|
19
|
-
|
20
|
-
runner = self.class.new(child_migration)
|
21
|
-
runner.run
|
22
|
-
end
|
19
|
+
if migration.attempts == 0
|
20
|
+
ActiveSupport::Notifications.instrument("started.background_schema_migrations", migration_payload)
|
23
21
|
else
|
24
|
-
|
22
|
+
ActiveSupport::Notifications.instrument("retried.background_schema_migrations", migration_payload)
|
25
23
|
end
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
def mark_as_running
|
30
|
-
Migration.transaction do
|
31
|
-
migration.running!
|
32
24
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
else
|
37
|
-
parent.update!(status: :running, started_at: Time.current, finished_at: nil)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
25
|
+
if should_throttle?
|
26
|
+
ActiveSupport::Notifications.instrument("throttled.background_schema_migrations", migration_payload)
|
27
|
+
return
|
41
28
|
end
|
42
29
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
migration.update!(
|
58
|
-
attempts: migration.attempts + 1,
|
59
|
-
status: :running,
|
60
|
-
started_at: Time.current,
|
61
|
-
finished_at: nil,
|
62
|
-
error_class: nil,
|
63
|
-
error_message: nil,
|
64
|
-
backtrace: nil
|
65
|
-
)
|
66
|
-
|
67
|
-
ActiveSupport::Notifications.instrument("run.background_schema_migrations", migration_payload) do
|
68
|
-
migration.run
|
69
|
-
end
|
70
|
-
|
71
|
-
# Background schema migrations could take a while to run. It is possible, that the process
|
72
|
-
# never reaches this (or the rescue below) line of code. E.g., when it is force quitted
|
73
|
-
# (SIGKILL etc.) and so the migration will end up in the "running" state and the query is
|
74
|
-
# still executing (or already finished) in the database. This migration can either be safely
|
75
|
-
# manually retried or will be picked up in the future by scheduler when it decides that
|
76
|
-
# this migration is stuck.
|
77
|
-
|
78
|
-
migration.update!(status: :succeeded, finished_at: Time.current)
|
30
|
+
migration.update!(
|
31
|
+
attempts: migration.attempts + 1,
|
32
|
+
status: :running,
|
33
|
+
started_at: Time.current,
|
34
|
+
finished_at: nil,
|
35
|
+
error_class: nil,
|
36
|
+
error_message: nil,
|
37
|
+
backtrace: nil
|
38
|
+
)
|
39
|
+
|
40
|
+
ActiveSupport::Notifications.instrument("run.background_schema_migrations", migration_payload) do
|
41
|
+
migration.run
|
42
|
+
end
|
79
43
|
|
80
|
-
|
44
|
+
# Background schema migrations could take a while to run. It is possible, that the process
|
45
|
+
# never reaches this (or the rescue below) line of code. E.g., when it is force quitted
|
46
|
+
# (SIGKILL etc.) and so the migration will end up in the "running" state and the query is
|
47
|
+
# still executing (or already finished) in the database. This migration can either be safely
|
48
|
+
# manually retried or will be picked up in the future by scheduler when it decides that
|
49
|
+
# this migration is stuck.
|
81
50
|
|
82
|
-
|
83
|
-
rescue Exception => e # rubocop:disable Lint/RescueException
|
84
|
-
backtrace_cleaner = ::OnlineMigrations.config.backtrace_cleaner
|
51
|
+
migration.update!(status: :succeeded, finished_at: Time.current)
|
85
52
|
|
86
|
-
|
53
|
+
ActiveSupport::Notifications.instrument("completed.background_schema_migrations", migration_payload)
|
54
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
55
|
+
backtrace_cleaner = ::OnlineMigrations.config.backtrace_cleaner
|
87
56
|
|
88
|
-
|
89
|
-
status: status,
|
90
|
-
finished_at: Time.current,
|
91
|
-
error_class: e.class.name,
|
92
|
-
error_message: e.message,
|
93
|
-
backtrace: backtrace_cleaner ? backtrace_cleaner.clean(e.backtrace) : e.backtrace
|
94
|
-
)
|
57
|
+
status = migration.attempts_exceeded? ? :failed : :errored
|
95
58
|
|
96
|
-
|
59
|
+
migration.update!(
|
60
|
+
status: status,
|
61
|
+
finished_at: Time.current,
|
62
|
+
error_class: e.class.name,
|
63
|
+
error_message: e.message,
|
64
|
+
backtrace: backtrace_cleaner ? backtrace_cleaner.clean(e.backtrace) : e.backtrace
|
65
|
+
)
|
97
66
|
|
98
|
-
|
99
|
-
|
100
|
-
|
67
|
+
::OnlineMigrations.config.background_schema_migrations.error_handler.call(e, migration)
|
68
|
+
raise if Utils.run_background_migrations_inline?
|
69
|
+
end
|
101
70
|
|
71
|
+
private
|
102
72
|
def should_throttle?
|
103
73
|
::OnlineMigrations.config.throttler.call
|
104
74
|
end
|
105
|
-
|
106
|
-
def complete_parent_if_needed(migration)
|
107
|
-
parent = migration.parent
|
108
|
-
completed = false
|
109
|
-
|
110
|
-
parent.with_lock do
|
111
|
-
children = parent.children.select(:status)
|
112
|
-
if children.all?(&:succeeded?)
|
113
|
-
parent.update!(status: :succeeded, finished_at: Time.current)
|
114
|
-
completed = true
|
115
|
-
elsif children.any?(&:failed?)
|
116
|
-
parent.update!(status: :failed, finished_at: Time.current)
|
117
|
-
completed = true
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
if completed
|
122
|
-
ActiveSupport::Notifications.instrument("completed.background_migrations", notifications_payload(migration))
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def notifications_payload(migration)
|
127
|
-
{ background_schema_migration: migration }
|
128
|
-
end
|
129
75
|
end
|
130
76
|
end
|
131
77
|
end
|
@@ -35,8 +35,8 @@ module OnlineMigrations
|
|
35
35
|
|
36
36
|
private
|
37
37
|
def find_migration(**options)
|
38
|
-
active_migrations = Migration.running.
|
39
|
-
runnable_migrations = Migration.
|
38
|
+
stuck_migrations, active_migrations = Migration.running.partition(&:stuck?)
|
39
|
+
runnable_migrations = (Migration.enqueued + Migration.errored + stuck_migrations).sort_by(&:created_at)
|
40
40
|
|
41
41
|
if options.key?(:shard)
|
42
42
|
runnable_migrations = runnable_migrations.select { |migration| migration.shard.to_s == options[:shard].to_s }
|
@@ -477,10 +477,11 @@ module OnlineMigrations
|
|
477
477
|
end
|
478
478
|
|
479
479
|
def __copy_check_constraints(table_name, from_column, to_column)
|
480
|
-
|
480
|
+
from_column_re = /\b#{from_column}\b/
|
481
|
+
check_constraints = check_constraints(table_name).select { |c| c.expression.match?(from_column_re) }
|
481
482
|
|
482
483
|
check_constraints.each do |check|
|
483
|
-
new_expression = check.expression.gsub(
|
484
|
+
new_expression = check.expression.gsub(from_column_re, to_column)
|
484
485
|
|
485
486
|
add_check_constraint(table_name, new_expression, validate: false)
|
486
487
|
|
@@ -210,10 +210,10 @@ module OnlineMigrations
|
|
210
210
|
|
211
211
|
# Configuration object to configure background migrations
|
212
212
|
#
|
213
|
-
# @return [
|
214
|
-
# @see
|
213
|
+
# @return [BackgroundDataMigrations::Config]
|
214
|
+
# @see BackgroundDataMigrations::Config
|
215
215
|
#
|
216
|
-
attr_reader :
|
216
|
+
attr_reader :background_data_migrations
|
217
217
|
|
218
218
|
attr_reader :background_schema_migrations
|
219
219
|
|
@@ -230,7 +230,7 @@ module OnlineMigrations
|
|
230
230
|
lock_timeout: 0.2.seconds
|
231
231
|
)
|
232
232
|
|
233
|
-
@
|
233
|
+
@background_data_migrations = BackgroundDataMigrations::Config.new
|
234
234
|
@background_schema_migrations = BackgroundSchemaMigrations::Config.new
|
235
235
|
|
236
236
|
@checks = []
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
gem "sidekiq", ">= 7.3.3"
|
4
|
+
require "sidekiq"
|
5
|
+
|
6
|
+
module OnlineMigrations
|
7
|
+
# Base class that is inherited by the host application's data migration classes.
|
8
|
+
class DataMigration
|
9
|
+
class NotFoundError < NameError; end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# Finds a Data Migration with the given name.
|
13
|
+
#
|
14
|
+
# @param name [String] the name of the Data Migration to be found.
|
15
|
+
#
|
16
|
+
# @return [DataMigration] the Data Migration with the given name.
|
17
|
+
#
|
18
|
+
# @raise [NotFoundError] if a Data Migration with the given name does not exist.
|
19
|
+
#
|
20
|
+
def named(name)
|
21
|
+
namespace = OnlineMigrations.config.background_data_migrations.migrations_module.constantize
|
22
|
+
internal_namespace = ::OnlineMigrations::BackgroundDataMigrations
|
23
|
+
|
24
|
+
migration = "#{namespace}::#{name}".safe_constantize ||
|
25
|
+
"#{internal_namespace}::#{name}".safe_constantize
|
26
|
+
|
27
|
+
raise NotFoundError.new("Data Migration #{name} not found", name) if migration.nil?
|
28
|
+
if !(migration.is_a?(Class) && migration < self)
|
29
|
+
raise NotFoundError.new("#{name} is not a Data Migration", name)
|
30
|
+
end
|
31
|
+
|
32
|
+
migration
|
33
|
+
end
|
34
|
+
|
35
|
+
# @private
|
36
|
+
attr_accessor :active_record_enumerator_batch_size
|
37
|
+
|
38
|
+
# Limit the number of records that will be fetched in a single query when
|
39
|
+
# iterating over an Active Record collection migration.
|
40
|
+
#
|
41
|
+
# @param size [Integer] the number of records to fetch in a single query.
|
42
|
+
#
|
43
|
+
def collection_batch_size(size)
|
44
|
+
self.active_record_enumerator_batch_size = size
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# A hook to override that will be called when the migration starts running.
|
49
|
+
#
|
50
|
+
def after_start
|
51
|
+
end
|
52
|
+
|
53
|
+
# A hook to override that will be called around 'process' each time.
|
54
|
+
#
|
55
|
+
# Can be useful for some metrics collection, performance tracking etc.
|
56
|
+
#
|
57
|
+
def around_process
|
58
|
+
yield
|
59
|
+
end
|
60
|
+
|
61
|
+
# A hook to override that will be called when the migration resumes its work.
|
62
|
+
#
|
63
|
+
def after_resume
|
64
|
+
end
|
65
|
+
|
66
|
+
# A hook to override that will be called each time the migration is interrupted.
|
67
|
+
#
|
68
|
+
# This can be due to interruption or sidekiq stopping.
|
69
|
+
#
|
70
|
+
def after_stop
|
71
|
+
end
|
72
|
+
|
73
|
+
# A hook to override that will be called when the migration finished its work.
|
74
|
+
#
|
75
|
+
def after_complete
|
76
|
+
end
|
77
|
+
|
78
|
+
# A hook to override that will be called when the migration is paused.
|
79
|
+
#
|
80
|
+
def after_pause
|
81
|
+
end
|
82
|
+
|
83
|
+
# A hook to override that will be called when the migration is cancelled.
|
84
|
+
#
|
85
|
+
def after_cancel
|
86
|
+
end
|
87
|
+
|
88
|
+
# The collection to be processed.
|
89
|
+
#
|
90
|
+
# @return [ActiveRecord::Relation, ActiveRecord::Batches::BatchEnumerator, Array, Enumerator]
|
91
|
+
#
|
92
|
+
# @raise [NotImplementedError] with a message advising subclasses to override this method.
|
93
|
+
#
|
94
|
+
def collection
|
95
|
+
raise NotImplementedError, "#{self.class.name} must implement a 'collection' method"
|
96
|
+
end
|
97
|
+
|
98
|
+
# The action to be performed on each item from the collection.
|
99
|
+
#
|
100
|
+
# @param _item the current item from the collection being iterated
|
101
|
+
# @raise [NotImplementedError] with a message advising subclasses to override this method.
|
102
|
+
#
|
103
|
+
def process(_item)
|
104
|
+
raise NotImplementedError, "#{self.class.name} must implement a 'process' method"
|
105
|
+
end
|
106
|
+
|
107
|
+
# Total count of iterations to be performed (optional, to be able to show progress).
|
108
|
+
#
|
109
|
+
# @return [Integer, nil]
|
110
|
+
#
|
111
|
+
def count
|
112
|
+
end
|
113
|
+
|
114
|
+
# Enumerator builder. You may override this method to return any Enumerator yielding
|
115
|
+
# pairs of `[item, item_cursor]`, instead of using `collection`.
|
116
|
+
#
|
117
|
+
# It is useful when it is not practical or impossible to define an explicit collection
|
118
|
+
# in the `collection` method.
|
119
|
+
#
|
120
|
+
# @param cursor [Object, nil] cursor position to resume from, or nil on initial call.
|
121
|
+
#
|
122
|
+
# @return [Enumerator]
|
123
|
+
#
|
124
|
+
def build_enumerator(cursor:)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -91,10 +91,13 @@ module OnlineMigrations
|
|
91
91
|
else
|
92
92
|
yield
|
93
93
|
end
|
94
|
-
rescue ActiveRecord::LockWaitTimeout
|
94
|
+
rescue ActiveRecord::LockWaitTimeout, ActiveRecord::Deadlocked => e
|
95
95
|
if current_attempt <= attempts
|
96
96
|
current_delay = delay(current_attempt)
|
97
|
-
|
97
|
+
|
98
|
+
problem = e.is_a?(ActiveRecord::Deadlocked) ? "Deadlock detected." : "Lock timeout."
|
99
|
+
Utils.say("#{problem} Retrying in #{current_delay} seconds...")
|
100
|
+
|
98
101
|
sleep(current_delay)
|
99
102
|
retry
|
100
103
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module OnlineMigrations
|
4
4
|
module SchemaStatements
|
5
5
|
include ChangeColumnTypeHelpers
|
6
|
-
include
|
6
|
+
include BackgroundDataMigrations::MigrationHelpers
|
7
7
|
include BackgroundSchemaMigrations::MigrationHelpers
|
8
8
|
|
9
9
|
# Updates the value of a column in batches.
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OnlineMigrations
|
4
|
+
module ShardAware
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_validation :set_connection_class_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_shard_if_present(&block)
|
12
|
+
if shard
|
13
|
+
connection_class.connected_to(shard: shard.to_sym, role: :writing, &block)
|
14
|
+
else
|
15
|
+
yield
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def connection_class_name=(value)
|
20
|
+
if value && (klass = value.safe_constantize)
|
21
|
+
if !(klass <= ActiveRecord::Base)
|
22
|
+
raise ArgumentError, "connection_class_name is not an ActiveRecord::Base child class"
|
23
|
+
end
|
24
|
+
|
25
|
+
connection_class = Utils.find_connection_class(klass)
|
26
|
+
super(connection_class.name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# @private
|
31
|
+
def connection_class
|
32
|
+
if connection_class_name && (klass = connection_class_name.safe_constantize)
|
33
|
+
Utils.find_connection_class(klass)
|
34
|
+
else
|
35
|
+
ActiveRecord::Base
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def set_connection_class_name
|
41
|
+
self.connection_class_name ||= "ActiveRecord::Base"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/online_migrations.rb
CHANGED
@@ -6,7 +6,8 @@ require "online_migrations/version"
|
|
6
6
|
require "online_migrations/utils"
|
7
7
|
require "online_migrations/background_schema_migrations/migration_helpers"
|
8
8
|
require "online_migrations/change_column_type_helpers"
|
9
|
-
require "online_migrations/
|
9
|
+
require "online_migrations/background_data_migrations/migration_helpers"
|
10
|
+
require "online_migrations/active_record_batch_enumerator"
|
10
11
|
require "online_migrations/schema_statements"
|
11
12
|
require "online_migrations/schema_cache"
|
12
13
|
require "online_migrations/migration"
|
@@ -29,7 +30,8 @@ module OnlineMigrations
|
|
29
30
|
autoload :ForeignKeysCollector
|
30
31
|
autoload :IndexDefinition
|
31
32
|
autoload :CommandChecker
|
32
|
-
autoload :
|
33
|
+
autoload :DataMigration
|
34
|
+
autoload :ShardAware
|
33
35
|
|
34
36
|
autoload_at "online_migrations/lock_retrier" do
|
35
37
|
autoload :LockRetrier
|
@@ -40,24 +42,21 @@ module OnlineMigrations
|
|
40
42
|
|
41
43
|
autoload :CopyTrigger
|
42
44
|
|
43
|
-
module
|
45
|
+
module BackgroundDataMigrations
|
44
46
|
extend ActiveSupport::Autoload
|
45
47
|
|
46
48
|
autoload :Config
|
47
49
|
autoload :MigrationStatusValidator
|
48
|
-
autoload :MigrationJobStatusValidator
|
49
|
-
autoload :BackgroundMigrationClassValidator
|
50
50
|
autoload :BackfillColumn
|
51
51
|
autoload :CopyColumn
|
52
52
|
autoload :DeleteAssociatedRecords
|
53
53
|
autoload :DeleteOrphanedRecords
|
54
54
|
autoload :PerformActionOnRelation
|
55
55
|
autoload :ResetCounters
|
56
|
-
autoload :MigrationJob
|
57
56
|
autoload :Migration
|
58
|
-
autoload :
|
59
|
-
autoload :MigrationRunner
|
57
|
+
autoload :MigrationJob
|
60
58
|
autoload :Scheduler
|
59
|
+
autoload :Ticker
|
61
60
|
end
|
62
61
|
|
63
62
|
module BackgroundSchemaMigrations
|
@@ -70,6 +69,10 @@ module OnlineMigrations
|
|
70
69
|
autoload :Scheduler
|
71
70
|
end
|
72
71
|
|
72
|
+
# Make aliases for less typing.
|
73
|
+
DataMigrations = BackgroundDataMigrations
|
74
|
+
SchemaMigrations = BackgroundSchemaMigrations
|
75
|
+
|
73
76
|
class << self
|
74
77
|
# @private
|
75
78
|
attr_accessor :current_migration
|
@@ -87,10 +90,10 @@ module OnlineMigrations
|
|
87
90
|
# @option options [String, Symbol, nil] :shard The name of the shard to run
|
88
91
|
# background data migrations on. By default runs on all shards.
|
89
92
|
#
|
90
|
-
def
|
91
|
-
|
93
|
+
def run_background_data_migrations(**options)
|
94
|
+
BackgroundDataMigrations::Scheduler.run(**options)
|
92
95
|
end
|
93
|
-
alias run_background_data_migrations
|
96
|
+
alias run_background_migrations run_background_data_migrations
|
94
97
|
|
95
98
|
# Run background schema migrations
|
96
99
|
#
|
@@ -122,6 +125,10 @@ module OnlineMigrations
|
|
122
125
|
else
|
123
126
|
ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache)
|
124
127
|
end
|
128
|
+
|
129
|
+
if !ActiveRecord::Batches::BatchEnumerator.method_defined?(:use_ranges)
|
130
|
+
ActiveRecord::Batches::BatchEnumerator.include(OnlineMigrations::ActiveRecordBatchEnumerator)
|
131
|
+
end
|
125
132
|
end
|
126
133
|
end
|
127
134
|
end
|