online_migrations 0.25.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/README.md +18 -73
  4. data/docs/0.27-upgrade.md +24 -0
  5. data/docs/background_data_migrations.md +200 -101
  6. data/docs/background_schema_migrations.md +2 -2
  7. data/docs/configuring.md +8 -0
  8. data/lib/generators/online_migrations/{background_migration_generator.rb → data_migration_generator.rb} +4 -4
  9. data/lib/generators/online_migrations/templates/add_sharding_to_online_migrations.rb.tt +1 -1
  10. data/lib/generators/online_migrations/templates/add_timestamps_to_background_migrations.rb.tt +1 -1
  11. data/lib/generators/online_migrations/templates/background_schema_migrations_change_unique_index.rb.tt +1 -1
  12. data/lib/generators/online_migrations/templates/change_background_data_migrations.rb.tt +34 -0
  13. data/lib/generators/online_migrations/templates/{background_data_migration.rb.tt → data_migration.rb.tt} +8 -9
  14. data/lib/generators/online_migrations/templates/initializer.rb.tt +22 -25
  15. data/lib/generators/online_migrations/templates/install_migration.rb.tt +9 -40
  16. data/lib/generators/online_migrations/upgrade_generator.rb +16 -8
  17. data/lib/online_migrations/active_record_batch_enumerator.rb +8 -0
  18. data/lib/online_migrations/background_data_migrations/backfill_column.rb +50 -0
  19. data/lib/online_migrations/background_data_migrations/config.rb +62 -0
  20. data/lib/online_migrations/{background_migrations → background_data_migrations}/copy_column.rb +15 -28
  21. data/lib/online_migrations/{background_migrations → background_data_migrations}/delete_associated_records.rb +9 -5
  22. data/lib/online_migrations/{background_migrations → background_data_migrations}/delete_orphaned_records.rb +5 -9
  23. data/lib/online_migrations/background_data_migrations/migration.rb +312 -0
  24. data/lib/online_migrations/{background_migrations → background_data_migrations}/migration_helpers.rb +72 -61
  25. data/lib/online_migrations/background_data_migrations/migration_job.rb +158 -0
  26. data/lib/online_migrations/background_data_migrations/migration_status_validator.rb +65 -0
  27. data/lib/online_migrations/{background_migrations → background_data_migrations}/perform_action_on_relation.rb +5 -5
  28. data/lib/online_migrations/{background_migrations → background_data_migrations}/reset_counters.rb +5 -5
  29. data/lib/online_migrations/background_data_migrations/scheduler.rb +78 -0
  30. data/lib/online_migrations/background_data_migrations/ticker.rb +62 -0
  31. data/lib/online_migrations/background_schema_migrations/config.rb +2 -2
  32. data/lib/online_migrations/background_schema_migrations/migration.rb +57 -127
  33. data/lib/online_migrations/background_schema_migrations/migration_helpers.rb +26 -47
  34. data/lib/online_migrations/background_schema_migrations/migration_runner.rb +43 -97
  35. data/lib/online_migrations/background_schema_migrations/scheduler.rb +2 -2
  36. data/lib/online_migrations/batch_iterator.rb +7 -4
  37. data/lib/online_migrations/change_column_type_helpers.rb +75 -14
  38. data/lib/online_migrations/command_checker.rb +32 -20
  39. data/lib/online_migrations/config.rb +12 -4
  40. data/lib/online_migrations/data_migration.rb +127 -0
  41. data/lib/online_migrations/error_messages.rb +16 -0
  42. data/lib/online_migrations/index_definition.rb +1 -1
  43. data/lib/online_migrations/lock_retrier.rb +5 -2
  44. data/lib/online_migrations/migration.rb +8 -1
  45. data/lib/online_migrations/schema_cache.rb +0 -78
  46. data/lib/online_migrations/schema_statements.rb +18 -74
  47. data/lib/online_migrations/shard_aware.rb +44 -0
  48. data/lib/online_migrations/utils.rb +1 -20
  49. data/lib/online_migrations/verbose_sql_logs.rb +1 -7
  50. data/lib/online_migrations/version.rb +1 -1
  51. data/lib/online_migrations.rb +19 -19
  52. metadata +25 -24
  53. data/lib/online_migrations/background_migration.rb +0 -64
  54. data/lib/online_migrations/background_migrations/backfill_column.rb +0 -54
  55. data/lib/online_migrations/background_migrations/background_migration_class_validator.rb +0 -29
  56. data/lib/online_migrations/background_migrations/config.rb +0 -74
  57. data/lib/online_migrations/background_migrations/migration.rb +0 -329
  58. data/lib/online_migrations/background_migrations/migration_job.rb +0 -109
  59. data/lib/online_migrations/background_migrations/migration_job_runner.rb +0 -66
  60. data/lib/online_migrations/background_migrations/migration_job_status_validator.rb +0 -29
  61. data/lib/online_migrations/background_migrations/migration_runner.rb +0 -161
  62. data/lib/online_migrations/background_migrations/migration_status_validator.rb +0 -48
  63. data/lib/online_migrations/background_migrations/scheduler.rb +0 -42
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6b7685527d71319ba50e3a5c29744d9ef28103c1cacfdc650cba12c276782d8
4
- data.tar.gz: e10e0d1dfb1c807b05927189f682633a7ab17c53f37974c5df5a2b452d78ab92
3
+ metadata.gz: 7125a034a085c11fff526219d8f2483dfea610b100486766145b7caf85e07700
4
+ data.tar.gz: 609636661c23e939a1766a14097fca30bc01b21666cfcb5e207bc20dfde4923c
5
5
  SHA512:
6
- metadata.gz: d7c62d15765a2837cf0dcba5e9a0c63c89ecc73f33fbd5500284184a78027f80a4ad12d980b5ac5de8235550384bd123708a075adab0243a06202154348268a3
7
- data.tar.gz: 24449c58e1bec9b3a31e925a27df17c56c7cd923f2cdd33a5d6781f1f253204776901e92fd4024d3340e4eeb533b043a71a1afeaacb046bcc6ea62d5e5444668
6
+ metadata.gz: 22866111b2a0ba3392d930c60548234f72c1f9dd27309a5b0c5ebff0b06232e5a59d2a6353db51d4c760abdafd90091a8ddf873808fb6cb53bbb755ebc7daf80
7
+ data.tar.gz: 16643b7af80d9d20e482a5be141e0ecd4733503ff9a80effcd03516af60270227c1c7d604b4b342c70a553e6fe729b83b9b8eb609f87cf9f5c6bde7e3177eb36
data/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  ## master (unreleased)
2
2
 
3
+ ## 0.27.0 (2025-05-01)
4
+
5
+ - **WARNING**: This release has breaking changes! See `docs/0.27-upgrade.md` for release notes
6
+
7
+ - Add ability to run background data migrations in parallel
8
+
9
+ ```ruby
10
+ # Run 2 data migrations in parallel.
11
+ OnlineMigrations.run_background_data_migrations(concurrency: 2)
12
+ ```
13
+
14
+ - Retry deadlocks by lock retrier
15
+ - Fix copying check constraints on columns with similar names when changing column type
16
+
17
+ ## 0.26.0 (2025-04-28)
18
+
19
+ - Drop support for Ruby < 3.1 and Rails < 7.1
20
+ - Add check for `change_column` for columns with check constraints
21
+
22
+ - Allow to require safety reason explanation when calling `safery_assured`
23
+
24
+ ```ruby
25
+ # config/initializers/online_migrations.rb
26
+ config.require_safety_assured_reason = true
27
+
28
+ # in migration
29
+ safety_assured("Table is small") do
30
+ add_index :users, :email, unique: true
31
+ end
32
+ ```
33
+
3
34
  ## 0.25.0 (2025-02-03)
4
35
 
5
36
  - Track start/finish time of background data migrations
data/README.md CHANGED
@@ -16,8 +16,8 @@ See [comparison to `strong_migrations`](#comparison-to-strong_migrations)
16
16
 
17
17
  ## Requirements
18
18
 
19
- - Ruby 3.0+
20
- - Rails 7.0+
19
+ - Ruby 3.1+
20
+ - Rails 7.1+
21
21
  - PostgreSQL 12+
22
22
 
23
23
  For older Ruby and Rails versions you can use older versions of this gem.
@@ -64,76 +64,32 @@ An operation is classified as dangerous if it either:
64
64
 
65
65
  ## Example
66
66
 
67
- Consider the following migration:
68
-
69
- ```ruby
70
- class AddAdminToUsers < ActiveRecord::Migration[8.0]
71
- def change
72
- add_column :users, :admin, :boolean, default: false, null: false
73
- end
74
- end
75
- ```
76
-
77
- If the `users` table is large, running this migration on a live PostgreSQL < 11 database will likely cause downtime.
78
-
79
- A safer approach would be to run something like the following:
80
-
81
- ```ruby
82
- class AddAdminToUsers < ActiveRecord::Migration[8.0]
83
- # Do not wrap the migration in a transaction so that locks are held for a shorter time.
84
- disable_ddl_transaction!
85
-
86
- def up
87
- # Lower PostgreSQL's lock timeout to avoid statement queueing.
88
- execute "SET lock_timeout TO '5s'" # The lock_timeout duration is customizable.
89
-
90
- # Add the column without the default value and the not-null constraint.
91
- add_column :users, :admin, :boolean
92
-
93
- # Set the column's default value.
94
- change_column_default :users, :admin, false
95
-
96
- # Backfill the column in batches.
97
- User.in_batches.update_all(admin: false)
98
-
99
- # Add the not-null constraint. Beforehand, set a short statement timeout so that
100
- # Postgres does not spend too much time performing the full table scan to verify
101
- # the column contains no nulls.
102
- execute "SET statement_timeout TO '5s'"
103
- change_column_null :users, :admin, false
104
- end
105
-
106
- def down
107
- remove_column :users, :admin
108
- end
109
- end
110
- ```
111
-
112
- When you actually run the original migration, you will get an error message:
67
+ When you run a migration that's potentially dangerous, you'll see an error message like:
113
68
 
114
69
  ```txt
115
70
  ⚠️ [online_migrations] Dangerous operation detected ⚠️
116
71
 
117
- Adding a column with a non-null default blocks reads and writes while the entire table is rewritten.
118
-
72
+ Active Record caches database columns at runtime, so if you drop a column, it can cause exceptions until your app reboots.
119
73
  A safer approach is to:
120
- 1. add the column without a default value
121
- 2. change the column default
122
- 3. backfill existing rows with the new value
123
- 4. add the NOT NULL constraint
124
74
 
125
- add_column_with_default takes care of all this steps:
75
+ 1. Ignore the column:
126
76
 
127
- class AddAdminToUsers < ActiveRecord::Migration[8.0]
128
- disable_ddl_transaction!
77
+ class User < ApplicationRecord
78
+ self.ignored_columns += ["name"]
79
+ end
129
80
 
130
- def change
131
- add_column_with_default :users, :admin, :boolean, default: false, null: false
81
+ 2. Deploy
82
+ 3. Wrap column removing in a safety_assured { ... } block
83
+
84
+ class RemoveColumn < ActiveRecord::Migration[8.0]
85
+ def change
86
+ safety_assured { remove_column :users, :name }
87
+ end
132
88
  end
133
- end
134
- ```
135
89
 
136
- It suggests how to safely implement a migration, which essentially runs the steps similar to described in the previous example.
90
+ 4. Remove column ignoring from step 1
91
+ 5. Deploy
92
+ ```
137
93
 
138
94
  ## Checks
139
95
 
@@ -1278,17 +1234,6 @@ Interesting reads:
1278
1234
  - [Stop worrying about PostgreSQL locks in your Rails migrations](https://medium.com/doctolib/stop-worrying-about-postgresql-locks-in-your-rails-migrations-3426027e9cc9)
1279
1235
  - [Avoiding integer overflows with zero downtime](https://buildkite.com/blog/avoiding-integer-overflows-with-zero-downtime)
1280
1236
 
1281
- ## Maybe TODO
1282
-
1283
- - support MySQL
1284
- - support other ORMs
1285
-
1286
- Background migrations:
1287
-
1288
- - extract as a separate gem
1289
- - add UI
1290
- - support batching over non-integer and multiple columns
1291
-
1292
1237
  ## Comparison to `strong_migrations`
1293
1238
 
1294
1239
  This gem was heavily inspired by the `strong_migrations` and GitLab's approaches to database migrations. This gem is a superset of `strong_migrations`, feature-wise, and has the same APIs.
@@ -0,0 +1,24 @@
1
+ # Upgrading to online_migrations 0.27.0
2
+
3
+ In this version, background data migrations internals were significantly refactored and rewritten, that allowed to make the gem much simpler and its API more flexible and not attached to a single use case (whole table data migrations). It relies on [Sidekiq's Iteration feature](https://github.com/sidekiq/sidekiq/wiki/Iteration), so having Sidekiq 7.3.3+ is a hard requirement for background data migrations feature to work now.
4
+
5
+ This is one of the preceding releases before v1.0.
6
+
7
+ To upgrade:
8
+
9
+ * Upgrade gem to v0.27: `gem 'online_migrations', '~> 0.27.0'`
10
+ * Upgrade the gem's initializer in `config/online_migrations.rb` by referring to the [newest contents](https://github.com/fatkodima/online_migrations/blob/master/lib/generators/online_migrations/templates/initializer.rb.tt)
11
+
12
+ If you don't use any of the [background data migrations](docs/background_data_migrations.md) or [background schema migrations](docs/background_schema_migrations.md), then this is probably all you need.
13
+
14
+ If you use background data migrations:
15
+
16
+ * Make sure all existing background data migrations completed before upgrading
17
+
18
+ * Get the latest schema changes
19
+ ```sh
20
+ $ bin/rails generate online_migrations:upgrade
21
+ $ bin/rails db:migrate
22
+ ```
23
+
24
+ Look at [background data migrations guide](docs/background_data_migrations.md) to find the API changes and new features.