Health Checks
Potions decides your app is up by requesting one path on it, the health check path. It defaults to /.
The path is used in two places:
- Zero downtime deploys. Potions requests the health check path during deployment. If it never passes, the new instance is stopped and your current release keeps serving.
- Uptime monitoring. If enabled, Potions requests your health check path and records the result on the app's Health Checks tab. Available on the Solo plan and up, with a verified primary domain.
Any 2xx or 3xx response passes. Redirects are not followed, and the request is a plain GET with no cookies or login session.
Setting the Path
- When adding an app: open Advanced options and set Health check path.
- Later: the app's Settings tab, Health check section. The change applies to the next deploy and the next uptime check.
The path is case-sensitive and can contain letters, numbers, dots, hyphens, underscores, tildes and slashes. Query strings aren't supported.
Adding a /health Route
/ works out of the box, but every check then renders your home page, and if / requires login the check is really testing your login redirect. A dedicated route is lighter and can't be broken by either. Phoenix doesn't generate one, so add a small plug and make it the first plug in your endpoint:
# lib/my_app_web/plugs/health_check.ex
defmodule MyAppWeb.Plugs.HealthCheck do
import Plug.Conn
def init(opts), do: String.split(Keyword.get(opts, :path, "/health"), "/", trim: true)
def call(%Plug.Conn{method: "GET", path_info: segments} = conn, segments) do
conn
|> put_resp_content_type("text/plain")
|> send_resp(200, "ok")
|> halt()
end
def call(conn, _segments), do: conn
end
# lib/my_app_web/endpoint.ex, right after `use Phoenix.Endpoint`
plug MyAppWeb.Plugs.HealthCheck, path: "/health"
Placed first, it answers before static files, sessions and request logging, so the check never shows up in your logs. Then set the health check path to /health.
If you want to ensure your database is reachable, you can run a simple query like Ecto.Adapters.SQL.query(MyApp.Repo, "SELECT 1") from the call/2 function.
When a Check Fails
See Troubleshooting Failed Deploys for what each status means.