-
Track start/finish time of background data migrations
Note: Make sure to run
bin/rails generate online_migrations:upgrade
if using background migrations. -
Add new state for errored background migrations
- errored - migration raised an error during last run
- failed - migration raises an error when running and retry attempts exceeded
-
Fix thread safety issue for lock retrier
Note: Lock retrier changed its API (
LockRetrier#connection
accessor was removed andLockRetrier#with_lock_retries
now accepts a connection argument). This change might be of interest if you implemented a custom lock retrier class.
-
Add ability to run a separate background migrations scheduler per shard
-
Revert "Prevent multiple instances of schedulers from being running simultaneously"
The feature was implemented using advisory locks, but they do not always play nicely with the database poolers, so the feature was reverted. It is expected now for user's code to prevent multiple instances of the schedulers from being run (by wrapping it into Redis lock etc).
-
Prevent multiple instances of schedulers from being running simultaneously
-
Reduce default batch sizes for background data migrations
batch_size
was 20_000, now 1_000;sub_batch_size
was 1_000, now 100 -
Remove deprecated code
-
Drop support for PostgreSQL < 12
-
Drop support for Ruby < 3.0 and Rails < 7.0
-
Make background data migrations scheduler run a single migration at a time
This is similar to background schema migrations scheduler's behavior. Running multiple migrations at a time can cause unneeded database load and other bad effects.
-
Add
#pausable?
,#can_be_cancelled?
and#can_be_paused?
helpers to background migrations
-
Fix
add_foreign_key
when referencing same table via different columns -
Make
validate_not_null_constraint
,remove_foreign_key
andremove_check_constraint
idempotent -
Add helpers for validating constraints in background
validate_foreign_key_in_background(:users, :companies) validate_constraint_in_background(:users, "first_name_not_null")
- Fix running background migrations over relations with duplicate records
- Fix background data migrations to work with
includes
/eager_load
on relation - Fix problem with running migrations for
activerecord
8.0.0.rc2
- Enhance columns removal check to check indexes
where
andinclude
options - Do not wait before running retried background migrations
- Fix
add_reference_concurrently
when adding non polymorphic references - Fix progress for background migrations with small number of records
- Fix
add_reference_concurrently
when adding polymorphic references
-
Fix an edge case for background schema migrations
If you use background schema migrations, you need to run
bin/rails generate online_migrations:upgrade bin/rails db:migrate
-
Fix retrying running stuck background schema migrations
-
Fix renaming columns for tables with long names
- Fix idempotency for
add_index
/remove_index
for expression indexes
- Fix
add_reference_concurrently
to be idempotent when adding a foreign key - Fix
enqueue_background_data_migration
to be idempotent
- Fix
add_index_in_background
to be idempotent
- Add ability to cancel background migrations
- Fix setting
started_at
/finished_at
for parents of sharded background schema migrations - Improve retrying of failed sharded background migrations
- Fix a bug when retried background data migration can not start
- Do not run multiple background schema migrations on the same table at the same time
- Fix raising in development when using sharding and background index creation/removal was not enqueued
- Fix background migrations
#progress
possibility to fail with zero division error - Add
ensure_background_data_migration_succeeded
andensure_background_schema_migration_succeeded
migration helpers - Raise in development when background index creation/removal was not enqueued
- Suggest two migrations for adding foreign keys
- Reraise errors when running background schema migrations inline
- Improve error message when background schema migration name is already taken
- Fix copying column background migration to work with primary keys added via
initialize_column_type_change
-
Add support for asynchronous creation/removal of indexes
See
docs/background_schema_migrations.md
for the feature description.
- Reraise errors when running background migrations inline
- Add
remove_background_migration
migration helper - Allow adding bigint foreign keys referencing integer primary keys
- Fix
add_reference_concurrently
to check for mismatched key types
- Fix
MigrationRunner
to considerrun_background_migrations_inline
proc
-
Add ability to configure whether background migrations should be run inline
The previous behavior of running inline in development and test environments is preserved, unless overriden.
config.run_background_migrations_inline = -> { Rails.env.local? }
- Fix calculation of batch ranges for background migration created with explicit ranges
-
Add ability to configure the path where generated background migrations will be placed
# It is placed in lib/ by default. config.background_migrations.migrations_path = "app/lib"
-
Reduce number of queries needed to calculate batch ranges for background migrations
-
Fix
finalize_column_type_change
to not recreate already existing indexes on the temporary column -
Remove potentially heavy queries used to get the ranges of a background migration
-
Require passing model name for background migration helpers when using multiple databases
-
Add
statement_timeout
configuration option -
Make
lock_timeout
argument optional forconfig.lock_retrier
This way, a default lock timeout value will be used (configured in
database.yml
or for the database user). -
Fix a bug that can lead to unfinished children of a sharded background migration
- Fix calculation of batch ranges for sharded background migrations
-
Support sharding for background migrations
Now, if a
relation
inside background migration definition is defined on a sharded model, then that background migration would automatically run on all the shards.To get all the new sharding related schema changes, you need to run:
$ bin/rails generate online_migrations:upgrade $ bin/rails db:migrate
-
Change background migration
progress
to return values in range from 0.0 to 100.0Previously, these were values in range from 0.0 to 1.0 and caused confusion
-
Copy exclusion constraints when changing column type
-
Update
revert_finalize_columns_type_change
to not remove indexes, foreign keys etc -
Fix verbose query logging when
ActiveRecord::Base.logger
isnil
-
Add a shortcut for running background migrations
# Before: OnlineMigrations::BackgroundMigrations::Scheduler.run # After OnlineMigrations.run_background_migrations
-
Add support for
:type_cast_function
toinitialize_column_type_change
helper -
Drop support for Ruby < 2.7 and Rails < 6.1
- Add
auto_analyze
configuration option - Add
alphabetize_schema
configuration option - Fix
backfill_column_for_type_change_in_background
for cast expressions - Fix copying indexes with long names when changing column type
- Enhance error messages with the link to the detailed description
- Fix checking which expression indexes to copy when changing column type
- Fix copying expression indexes when changing column type
-
Add ability to use custom raw sql for
backfill_column_for_type_change
'stype_cast_function
backfill_column_for_type_change(:users, :company_id, type_cast_function: Arel.sql("company_id::integer"))
-
Fix version safety with
revert
- Promote check constraint to
NOT NULL
on PostgreSQL >= 12 when changing column type - Fix
safety_assured
withrevert
- Fix
update_columns_in_batches
when multiple columns are passed - Fix reverting adding/removing not null and text limit constraints
- Add check for
change_column_default
- Add check for
add_unique_constraint
(Active Record >= 7.1) - Add check for
add_column
with stored generated columns
- Fix removing columns having expression indexes on them
- Suggest additional steps for safely renaming a column if Active Record
enumerate_columns_in_select_statements
setting is enabled (implemented in Active Record 7+, disabled by default) - Fix
add_reference_concurrently
to correctly check for existence of foreign keys - Fix column quoting in
add_not_null_constraint
- Fix Schema Cache to correctly retrieve metadata from renamed tables
- Add support for renaming multiple columns at once in the same table
- Fix quoting table/column names across the library
- Fix deffered foreign keys support in
add_foreign_key
(Active Record >= 7) - Reset attempts of failing jobs before executing background migration inline
- Ignore internal Active Record migrations compatibility related options when suggesting a safe column type change
- Added check for
add_exclusion_constraint
- Fix preserving old column options (
:comment
and:collation
) when changing column type - Set
NOT NULL
during new column creation when changing column type for PostgreSQL >= 11
- Support ruby 3.2.0
- Fix removing index by name
- Fix multiple databases support for
start_after
andtarget_version
configs - Fix error when
Rails
defined withoutRails.env
- Improve error message for adding column with a NULL default for PostgreSQL < 11
-
Fix sequence resetting in tests that use fixtures
-
Fix
update_column_in_batches
for SQL subquery valuesIt generated inefficient queries before, e.g.:
update_column_in_batches(:users, :comments_count, Arel.sql(<<~SQL)) (select count(*) from comments where comments.user_id = users.id) SQL
Generated SQL queries before:
update users set comments_count = (..count subquery..) where comments_count is null or comments_count != (..count subquery..)
Generated SQL queries now:
update users set comments_count = (..count subquery..)
-
Fix check for
add_column
withdefault: nil
for PostgreSQL < 11 -
Replacing a unique index when other unique index with the prefix of columns exists is safe
- Raise for possible index corruption in all environments (previously, the check was made only in the production environment)
-
Added check for index corruption with PostgreSQL 14.0 to 14.3
-
No need to separately remove indexes when removing a column from the small table
-
Add ability to perform specific action on a relation or individual records using background migrations
Example, assuming you have lots and lots of fraud likes:
class DeleteFraudLikes < ActiveRecord::Migration[7.0] def up perform_action_on_relation_in_background("Like", { fraud: true }, :delete_all) end end
Example, assuming you added a new column to the users and want to populate it:
class User < ApplicationRecord def generate_invite_token self.invite_token = # some complex logic end end perform_action_on_relation_in_background("User", { invite_token: nil }, :generate_invite_token)
You can use
delete_all
/destroy_all
/update_all
for the whole relation or run specific methods on individual records. -
Add ability to delete records associated with a parent object using background migrations
class Link < ActiveRecord::Base has_many :clicks end class Click < ActiveRecord::Base belongs_to :link end class DeleteSomeLinkClicks < ActiveRecord::Migration[7.0] def up some_link = ... delete_associated_records_in_background("Link", some_link.id, :clicks) end end
-
Add ability to delete orphaned records using background migrations
class User < ApplicationRecord has_many :posts end class Post < ApplicationRecord belongs_to :author, class_name: 'User' end class DeleteOrphanedPosts < ActiveRecord::Migration[7.0] def up delete_orphaned_records_in_background("Post", :author) end end
- Fix missing options in suggested command for columns removal
- Fix retrieving raw postgresql connection
-
Lazy load this gem
-
Add ability to reset counter caches using background migrations
class User < ApplicationRecord has_many :projects end class Project < ApplicationRecord belongs_to :user, counter_cache: true end class ResetUsersProjectsCount < ActiveRecord::Migration[7.0] def up reset_counters_in_background("User", :projects) end end
-
Accept
0
asbatch_pause
value for background migrations -
Ignore default scopes in
CopyColumn
andBackfillColumn
background migrations -
Raise an error for unsupported database versions
-
Fix backfilling code in suggestion for changing column's NOT NULL
New safe operations
- Changing between
text
andcitext
when not indexed - Changing a
string
column to acitext
column when not indexed - Changing a
citext
column to astring
column with no length limit - Increasing the
:precision
of aninterval
column - Changing a
cidr
column to aninet
column - Changing an
xml
column to atext
column - Changing an
xml
column to astring
column with no:limit
- Changing a
bit
column to abit_varying
column - Increasing or removing the
:limit
of abit_varying
column
New unsafe operations
- Decreasing
:precision
of adatetime
column - Decreasing
:limit
of atimestamptz
column - Decreasing
:limit
of abit_varying
column - Adding a
:limit
to abit_varying
column
-
Support ActiveRecord 7.0+ versioned schemas
-
Check for addition of single table inheritance column
See Adding a single table inheritance column for details
-
Add a way to log every SQL query to stdout
See Verbose SQL logs for details
-
Ignore new tables when checking for removing table with multiple fkeys
-
Fix backfilling column in add_column_with_default when default is an expression
-
Check removing a table with multiple foreign keys
-
Check for mismatched reference column types
For example, it detects cases like:
class AddUserIdToProjects < ActiveRecord::Migration[7.0] def change add_column :projects, :user_id, :integer end end
where
users.id
is of typebigint
. -
Add support for multiple databases to
start_after
andtarget_version
configuration optionsOnlineMigrations.configure do |config| config.start_after = { primary: 20211112000000, animals: 20220101000000 } config.target_version = { primary: 10, animals: 14.1 } end
-
Do not suggest
ignored_columns
when removing columns for Active Record 4.2 (ignored_columns
was introduced in 5.0) -
Check replacing indexes
For example, you have an index on
projects.creator_id
. But decide, it is better to have a multicolumn index on[creator_id, created_at]
:class AddIndexOnCreationToProjects < ActiveRecord::Migration[7.0] disable_ddl_transaction! def change remove_index :projects, :creator_id, algorithm: :concurrently # (1) add_index :projects, [:creator_id, :created_at], algorithm: :concurrently # (2) end end
If there is no existing indexes covering
creator_id
, removing an old index (1) before replacing it with the new one (2) might result in slow queries while building the new index. A safer approach is to swap removing the old and creation of the new index operations.
- First release