Packages

Library for tracking HTTP status code rates and service health monitoring

Current section

Files

Jump to
status_code_tracker lib status_code_tracker health_plug.ex
Raw

lib/status_code_tracker/health_plug.ex

defmodule StatusCodeTracker.HealthPlug do
@default_path "/health"
@moduledoc """
A plug for responding to heartbeat requests.
This plug responds with a successful status to `GET` or `HEAD` requests at a
specific path so that clients can check if a server is alive.
The response that this plug sends is a *200 OK* response with body `OK`. By
default, the path that responds to the heartbeat is `#{@default_path}`, but it
can be configured.
Note that this plug **halts the connection**. This is done so that it can be
plugged near the top of a plug pipeline and catch requests early so that
subsequent plugs don't have the chance to tamper the connection.
Read more about halting connections in the [docs for
`Plug.Builder`](http://hexdocs.pm/plug/Plug.Builder.html).
## Options
The following options can be used when calling `plug PlugHeartbeat`.
* `:path` - a string expressing the path on which `PlugHeartbeat` will be mounted to
respond to heartbeat requests
* `:json` - a boolean which determines whether the response will be an
`application/json` response (if `true`) or a regular response.
## Examples
defmodule MyEndpoint do
use Plug.Builder
plug StatusCodeTracker.HealthPlug
# ... rest of the pipeline
end
defmodule MyServerWeb.Router do
use Plug.Builder
plug StatusCodeTracker.HealthPlug
scope "/health" do
get("/", StatusCodeTracker.HealthPlug, [])
end
# ... rest of the router
end
Using a custom heartbeat path is easy:
defmodule MyEndpoint do
use Plug.Builder
plug StatusCodeTracker.HealthPlug, path: "/heartbeat"
# ... rest of the pipeline
end
"""
@behaviour Plug
import Plug.Conn
def init(opts),
do: Keyword.merge([path: @default_path, json: false], opts)
def call(%Plug.Conn{} = conn, opts) do
if conn.request_path == opts[:path] and conn.method in ~w(GET HEAD) do
check_health(conn, opts)
else
conn
end
end
defp check_health(conn, opts) do
if StatusCodeTracker.Server.health_check_pass?(),
do: conn |> halt |> send_beat(opts[:json], opts),
else:
send_resp(
conn,
StatusCodeTracker.Server.unhealthy_status_code(),
"Service unhealthy due to many 5xx"
)
end
defp send_beat(conn, false = _json, opts),
do: send_resp(conn, 200, opts[:body] || "OK")
defp send_beat(conn, true = _json, opts) do
body = opts[:body] || "{}"
conn
|> put_resp_content_type("application/json")
|> send_resp(200, opts[:body])
end
end