summaryrefslogtreecommitdiff
path: root/doc/development/database/avoiding_downtime_in_migrations.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/database/avoiding_downtime_in_migrations.md')
-rw-r--r--doc/development/database/avoiding_downtime_in_migrations.md62
1 files changed, 58 insertions, 4 deletions
diff --git a/doc/development/database/avoiding_downtime_in_migrations.md b/doc/development/database/avoiding_downtime_in_migrations.md
index b34c0bbf728..bb6e13eff53 100644
--- a/doc/development/database/avoiding_downtime_in_migrations.md
+++ b/doc/development/database/avoiding_downtime_in_migrations.md
@@ -282,6 +282,62 @@ Example migration:
end
```
+## Changing column defaults
+
+Changing column defaults is difficult because of how Rails handles values
+that are equal to the default.
+
+If running code ever explicitly writes the old default value of a column, you must follow a multi-step
+process to prevent Rails replacing the old default with the new default in INSERT queries that explicitly
+specify the old default.
+
+Doing this requires steps in two minor releases:
+
+1. Add the `SafelyChangeColumnDefault` concern to the model and change the default in a post-migration.
+1. Clean up the `SafelyChangeColumnDefault` concern in the next minor release.
+
+We must wait a minor release before cleaning up the `SafelyChangeColumnDefault` because self-managed
+releases bundle an entire minor release into a single zero-downtime deployment.
+
+### Step 1: Add the `SafelyChangeColumnDefault` concern to the model and change the default in a post-migration
+
+The first step is to mark the column as safe to change in application code.
+
+```ruby
+class Ci::Build < ApplicationRecord
+ include SafelyChangeColumnDefault
+
+ columns_changing_default :partition_id
+end
+```
+
+Then create a **post-deployment migration** to change the default:
+
+```shell
+bundle exec rails g post_deployment_migration change_ci_builds_default
+```
+
+```ruby
+class ChangeCiBuildsDefault < Gitlab::Database::Migration[2.1]
+ def up
+ change_column_default('ci_builds', 'partition_id', from: 100, to: 101)
+ end
+
+ def down
+ change_column_default('ci_builds', 'partition_id', from: 101, to: 100)
+ end
+end
+```
+
+You can consider [enabling lock retries](../migration_style_guide.md#usage-with-transactional-migrations)
+when you run a migration on big tables, because it might take some time to
+acquire a lock on this table.
+
+### Step 2: Clean up the `SafelyChangeColumnDefault` concern in the next minor release
+
+In the next minor release, create a new merge request to remove the `columns_changing_default` call. Also remove the `SafelyChangeColumnDefault` include
+if it is not needed for a different column.
+
## Changing The Schema For Large Tables
While `change_column_type_concurrently` and `rename_column_concurrently` can be
@@ -319,10 +375,8 @@ This operation is safe as there's no code using the table just yet.
Dropping tables can be done safely using a post-deployment migration, but only
if the application no longer uses the table.
-Add the table to `DELETED_TABLES` in
-[gitlab_schema.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/database/gitlab_schema.rb),
-along with its `gitlab_schema`. Even though the table is deleted, it is still
-referenced in database migrations.
+Add the table to [`db/docs/deleted_tables`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/db/docs/deleted_tables) using the process described in [database dictionary](database_dictionary.md#dropping-tables).
+Even though the table is deleted, it is still referenced in database migrations.
## Renaming Tables