Easier Laravel DB Migrations With Zero Downtime

When Laravel is paired with a Mysql DB it can be increasingly difficult to make changes as the installation grows in popularity. While Mysql is getting better with its Online DDL there are still some limitations. And even with the latest online tools Laravel’s built-in migration scripts won’t consistently use them without specialized code. To make minimal-downtime changes easier I’ve helped create an adapter for Percona’s Online-Schema Change (PTOSC) and Mysql’s Online DDL called laravel-online-migrator (LOM).

Consider a Laravel DB migration adding a column: Schema::table('my_table', function (Blueprint $table) { $table->string('color', 64)->nullable(); }); To use PTOSC the queries have to be manually written as shell commands: pt-online-schema-change D=homestead,t=my_table,h=localhost \ --user=homestead --password=secret \ --alter "ADD color VARCHAR(64)" --execute Then it must be wrapped in a PHP function like exec, or run outside the normal Artisan migrate workflow. When done outside migrate a row must be inserted into the “migrations” table for each migration, unless Laravel’s built-in migrations will never be run.

Now with laravel-online-migrator the migration script can remain unchanged. When migrate is run the script is automatically changed from this PHP code$table->string('color', 64)->nullable(); to this command pt-online-schema-change D=homestead,t=my_table,h=localhost \ --user=homestead --password=secret \ --alter "ADD color VARCHAR(64)" --execute and the command is run.

Before executing migrations the generated commands can also be reviewed for correctness with --pretend like this php artisan migrate --pretend Pretending can be helpful when one is unsure what the adapter will do. When using PTOSC that output can also be copied and pasted into a shell with the --execute flag replaced with --dry-run. Dry runs will confirm with PTOSC whether or not the command is ready before the original table is modified.

LOM tries to be flexible: not changing queries unnecessarily and supporting common ‘raw’ queries as well. So dropping a table won’t go through PTOSC, or if migrations rely on hand-written SQL then they should work without human intervention. For example a raw query like \DB::statement("ALTER TABLE my_table CHANGE fruit fruit ENUM('apple', 'orange')"); will be translated to a PTOSC command, while \DB::statement("DROP TABLE my_table CASCADE"); will remain unchanged.

Fine-grained control of which online tool–if any–is used can be found within the configuration file config/online-migrator.php, environment variables like ONLINE_MIGRATOR, and traits on the migration scripts themselves. For more see the documentation on usage. Also of note, the output of “php artisan migrate” will be more verbose in order to aid resolving problems with migration runs.

UPDATE 2019-02-05: Forgot to mention the convenience option doctrine-enum-mapping was included to make changing tables with DB enumerations easier. By setting its value to ‘string’ migrations can use Eloquent code to change enum-equipped tables, though yet not for changing the enum columns themselves.

If this has been helpful please consider commenting here or opening an issue or pull request on the project’s Github.

NOTE: All opinions and thoughts expressed here are my own and do not reflect those of my employer.