# PhoenixHealthy

Kubernetes liveness and readiness probes for Phoenix (and Plug).

Default endpoints:

- `GET /health/live` — process is up (`200 ok`)
- `GET /health/ready` — app can accept traffic (`200 ok` or `503 unavailable`)

When a `:repo` is configured, readiness runs `SELECT 1` through `Ecto.Adapters.SQL`.

## Installation

```elixir
def deps do
  [
    {:phoenix_healthy, "~> 0.1.0"}
  ]
end
```

## Usage

### Router (Phoenix)

```elixir
defmodule MyAppWeb.Router do
  use MyAppWeb, :router
  import PhoenixHealthy.Router

  phoenix_healthy("/health", repo: MyApp.Repo)
end
```

This exposes `GET /health/live` and `GET /health/ready`.

Or configure the repo once:

```elixir
# config/config.exs
config :phoenix_healthy, repo: MyApp.Repo
```

```elixir
import PhoenixHealthy.Router
phoenix_healthy("/health")
```

### Endpoint plug

Place it near the top of `endpoint.ex` so probes skip the rest of the pipeline (sessions, parsers, request logs):

```elixir
defmodule MyAppWeb.Endpoint do
  use Phoenix.Endpoint, otp_app: :my_app_web

  plug PhoenixHealthy.Plug, repo: MyApp.Repo
  # ...
end
```

### Your own controller (Swagger, custom plugs)

```elixir
defmodule MyAppWeb.HealthController do
  use MyAppWeb, :controller
  use PhoenixHealthy, repo: MyApp.Repo
end
```

```elixir
pipeline :health do
  plug :accepts, ["html", "text", "json"]
end

scope "/health", MyAppWeb do
  pipe_through :health
  get "/live", HealthController, :live
  get "/ready", HealthController, :ready
end
```

## Options

| Option | Default | Description |
| --- | --- | --- |
| `:repo` | `nil` | Ecto repo used for the default readiness check |
| `:path` | `"/health"` | Base path for `PhoenixHealthy.Plug` |
| `:live_path` | `"live"` | Liveness segment |
| `:ready_path` | `"ready"` | Readiness segment |
| `:live` | always ok | Custom liveness probe (`() -> probe_result`) or MFA |
| `:ready` | repo check, else ok | Custom readiness probe (`() -> probe_result`) or MFA |
| `:ok_body` | `"ok"` | Body for a passing probe |
| `:error_body` | `"unavailable"` | Body for a failing probe |

A probe may return `:ok`, `true`, `:error`, `false`, or `{:error, reason}`.

Custom readiness (for example Redis + DB):

```elixir
phoenix_healthy("/health",
  ready: fn ->
    with :ok <- PhoenixHealthy.Checks.ecto(MyApp.Repo),
         :ok <- MyApp.Redis.ping() do
      :ok
    end
  end
)
```

## Kubernetes

```yaml
livenessProbe:
  httpGet:
    path: /health/live
    port: http
readinessProbe:
  httpGet:
    path: /health/ready
    port: http
```
