We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Sometimes, it is very useful to read the manual. I was searching for a way to run custom commands for a Phoenix release and found the solution in the manual:
A common need in production systems is to execute custom commands required to set up the production environment. One of such commands is precisely migrating the database. Since we don't have
Mix
, a build tool, inside releases, which are a production artifact, we need to bring said commands directly into the release.The
phx.gen.release
command created the followingrelease.ex
file in your projectlib/my_app/release.ex
, with the following content:defmodule MyApp.Release do @app :my_app def migrate do load_app() for repo <- repos() do {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true)) end end def rollback(repo, version) do load_app() {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version)) end defp repos do Application.fetch_env!(@app, :ecto_repos) end defp load_app do Application.load(@app) end end
Where you replace the first two lines by your application names.
Now you can assemble a new release with
MIX_ENV=prod mix release
and you can invoke any code, including the functions in the module above, by calling theeval
command:_build/prod/rel/my_app/bin/my_app eval "MyApp.Release.migrate"
And that's it! If you peek inside the migrate script, you'll see it wraps exactly this invocation.
You can use this approach to create any custom command to run in production. In this case, we used
load_app
, which callsApplication.load/1
to load the current application without starting it. However, you may want to write a custom command that starts the whole application. In such cases,Application.ensure_all_started/1
must be used. Keep in mind, starting the application will start all processes for the current application, including the Phoenix endpoint. This can be circumvented by changing your supervision tree to not start certain children under certain conditions. For example, in the release commands file you could do:defp start_app do load_app() Application.put_env(@app, :minimal, true) Application.ensure_all_started(@app) end
And then in your application you check
Application.get_env(@app, :minimal)
and start only part of the children when it is set.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.