Can a Doctrine Migrations rollback ever be safe after a destructive schema change in production?
0 reputation · 12 Nov 2023, 00:26 UTC
0 reputation · 12 Nov 2023, 00:26 UTC
In a Symfony application using Doctrine Migrations, I am planning a release that includes a destructive schema change (dropping a column that existing code still reads). I want a rollback plan I can actually trust, but the more I look at how migrations work, the less clear the safe path is.
My understanding is that doctrine:migrations:migrate with a target version simply executes the down() methods, and a down() that recreates a dropped column cannot restore the data that was in it. I also believe DDL behaves differently per platform: on MySQL/MariaDB a failed migration may leave the schema half-migrated because of implicit commits, while PostgreSQL can wrap DDL in a transaction. On top of that, the bundle tracks executed versions in a table, so reverting schema manually without rolling back the version row would leave state inconsistent.
Assume a current Symfony 6/7 application with doctrine/migrations 3.x on MariaDB, verified against my installed versions.
Given that, is the accepted practice to split destructive changes across two deploys (code tolerant of both schemas first, drop the column later) so rollback never needs to undo data loss? If a destructive migration has already shipped, is a database backup plus a compensating data migration the only real recovery option, since down() alone cannot restore rows? And does doctrine:migrations:diff pose a risk here, in that re-running it after a rollback could regenerate the same DROP statements while the mapping metadata still differs?
31275 reputation · 12 Nov 2023, 11:01 UTC
No, a Doctrine Migrations rollback is never safe for data recovery after a destructive schema change. While the down() method can restore the table structure (the schema), it cannot restore the data that was deleted during the up() phase. A rollback in this context only restores the capability to store data in that column, not the data itself.
Doctrine Migrations are primarily DDL (Data Definition Language) tools. When you execute a rollback, Doctrine simply runs the SQL defined in the down() method. If your up() method contained ALTER TABLE ... DROP COLUMN x, the down() method will likely contain ALTER TABLE ... ADD COLUMN x. This creates an empty column; it does not trigger a magic recovery of the dropped values.
As noted in your environment (MariaDB), DDL statements trigger implicit commits. If a migration contains multiple schema changes and fails halfway through, MariaDB cannot roll back the successful statements. This leaves your database in a "partial state" where the version table may not reflect the actual schema, making a standard doctrine:migrations:migrate rollback potentially hazardous or prone to SQL errors.
doctrine:migrations:diffRunning migrations:diff after a rollback is risky if your PHP entities (mapping metadata) have not been reverted to the previous version. The diff tool compares the current database state to the current entity mapping. If the mapping still reflects the "new" state (column removed) but the database was rolled back to the "old" state (column exists), the diff will generate a new migration to drop that column again.
To avoid the need for data-restoring rollbacks, use a multi-phase deployment strategy:
DROP the column.If a destructive migration has already shipped and you must recover, the only viable paths are:
Diagnostic Detail Needed: Are you using a blue-green deployment strategy or a single-server atomic swap? This determines if you can simply point traffic back to an old database instance rather than attempting a schema rollback.
Use comments to ask for clarification. Post a solution as an answer.
31,275 reputation · 12 Nov 2023, 01:40 UTC
One way to retain the ability to rollback a destructive column drop is to copy the column’s data to a temporary table in the up() method, drop the column, then in down() recreate the column and restore the data from that temporary table before dropping the table.