Minimalistic migrations in Elixir releases
Ensure your schemas are always in place, in under ten lines of code
2019-11-01
If you’re deploying your Elixir project as an OTP release (as opposed to,
say, pulling your entire repo and running iex -S mix
in production, which you
shouldn’t do), you’ve probably run across the problem of ensuring your Ecto
migrations run before your application starts.
There are several blog and forum posts out there talking about running migrations as part of the Elixir release startup process. I’m probably not going to add extra value if you already have your workflow figured out, but if you’re just getting started and happen to be using the new release configuration functionality in Elixir, you’ll be happy to know that this problem can be golfed to under 10 lines of code, and no extra dependencies.
Here goes. In config/releases.exs
, you need 1 line:
MyApp.ReleaseTasks.migrate()
Now, for the implementation module:
defmodule MyApp.ReleaseTasks do
def migrate do
{:ok, _} = Application.ensure_all_started(:my_app)
path = Application.app_dir(:my_app, "priv/repo/migrations")
Ecto.Migrator.run(MyApp.DA.Repo, path, :up, all: true)
end
end
Ecto.Migrator.run
will return a list of integers representing the migrations
that were actually applied, so an extra 2 lines of code will give you a nice diagnostic log message:
defmodule MyApp.ReleaseTasks do
require Logger
def migrate do
{:ok, _} = Application.ensure_all_started(:my_app)
path = Application.app_dir(:my_app, "priv/repo/migrations")
applied = Ecto.Migrator.run(MyApp.DA.Repo, path, :up, all: true)
Logger.info("Applied migrations: #{applied}")
end
end