What is this about?
When buliding Elixir applications we often need to run some code on application startup. For example, we may want to run database migrations, attach telemetry handlers, or perform some additional checks.
Is it usually most useful to perform these actions before you start the HTTP Endpoint and the application starts accepting requests. This will allow the deployment system (or load balancer) to check that the application is healthy before sending traffic to it.
How to?
Create a new Startup
module in your application:
defmodule MyApp.Startup do
# Capture compile-time environment
@compile_env Mix.env()
def child_spec(_opts) do
%{
id: __MODULE__,
start: {__MODULE__, :start_link, []},
# The child process is restarted only if it terminates abnormally
restart: :transient
}
end
def start_link do
# We could start a process here, but we don't need to.
# Instead, we can just run the code we need to run on startup.
startup(@compile_env)
# Returning `:ignore` from `start_link/0` callback
# tells the supervisor that everything is fine and to ignore this child.
:ignore
end
defp startup(:test) do
# Skip any startup code in test environment
:ok
end
defp startup(_dev_or_prod) do
# This is just an example. You can run any code here.
# Migrate on app startup
Ecto.Migrator.run(MyApp.Repo, :up, all: true)
# Perform any other actions
attach_telemetry_handlers()
# Run checks against third-party API
check_api_credentials()
end
defp attach_telemetry_handlers do
# ...
end
defp check_api_credentials do
case MyApp.ImportantApi.ping() do
{:error, :unauthorized} ->
# Raise an exception to prevent the application from starting
raise "Invalid API credentials"
# ...
end
end
end
Then include the Startup
module in the list of children in your application’s supervisor children list:
defmodule MyApp.Application do
def start(_type, _args) do
children = [
# ...
# Add your Startup module to list before the Endpoint
MyApp.Startup,
MyAppWeb.Endpoint,
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end