I remember reading about elixir “Hot swap” and vaguely remember reading that updates can be made unobtrusively.
Is there a way to perform phoenix migration updates in a “hot swap” way where the user doesn’t notice the disruption? I am in the middle of some work and this popped into my head and thought I would ask.
If you use the mix phx.gen.release generator, you will create the following file:
lib/app_name/release.ex
- A release module containing tasks for running migrations inside a release
This is a module that contains functions that can run migrations without mix, usually used in production. You can use it to customize when you want to run the migrations.
It is important to keep in mind that there will be always be a race condition when doing this when the system is running, especially if you are using things like ecto schemas, so in general cases it is advised to run migrations before starting the server.
It depends on the migration and what changes in the database it makes, but also your deployment strategy.
Generally, the answer is “Yes”. But you have to think about it.
Let’s have a look how migrations are typically run during deployment, and I assume you’re doing a deployment without downtime here. Let’s say you have running version A of the software, and then you are going to deploy version B of the software, that uses the migration.
In typical scenario, during deployment the following things would happen:
-
A B version of the application is deployed somewhere, on a container or on the server, but it’s not started just yet.
-
Version A keeps running
-
On the version B of the software, migrations run
-
Version B of the software starts up
-
Once 4) is complete, version A of the software stops running.
Now, if that’s your deployment scenario, that means you can break version A of the software with your migration. The race condition is on the step 3, when version B runs migrations, but version A keeps running. Typically, that would happen if you remove a table or a column that version A of the software users.
You can mitigate that by introducing version C of the software, deployed just after version B, that will take care of any destructive actions that would affect version A of the software, but will not affect version B.
Here is my scenario.
I have a localhost machine running a replica of the live app. The localhost machine is where I run migration files and update pages that use the newly created table data.
After I validate that it works, I copy the files to the Live Instance, run the migration commands etc.
There is no B server.
The “disruption” to the user is minimal as this is a private in-house tool I wrote, but I was still curious if there is a way to do this without the small hiccup.
You need at least two instances (of your app) to not have downtime. They need to run concurrently for at least the time it takes for the new instance to start up before the old one can start shutting down.
Yes there are many database migration tools to do zero downtime migrations aka “hot swap migrations”.
Reshape is a recent tool for Postgres to do zero downtime migrations and preserve compatibility so you can do gradual rollout of your application.
You won’t be writing Ecto migrations however as it provides its own migration definitions to ensure safe non locking/blocking constructs are used to not impact running apps, hence zero downtime.
Reshape is written in Rust and its not very large. It would not be that difficult to use a similar approach in Elixir / Ecto to provide a new multiphased zero downtime approach to migrations.
In the meantime nothing stops you managing migrations however you like.