defmodule Integrations.HttpAbsent do @moduledoc """ HTTP absence check. The inverse of the HTTP integration: healthy when the URL is *not* reachable, down when it is. Useful for verifying a decommissioned service is gone, a firewall rule is blocking a destination, or a site is intentionally offline. Collection only — see `Integrations.HttpAbsent.Display` (same package) for the dashboard panel. `Display.BundledDefault` auto-hooks it whenever this monitor starts, same as a single-module package would; a release without `raven_web` simply never compiles the display half and runs this monitor headless. ## Params * `:url` — The URL to check. Required. * `:timeout_ms` — Request timeout in milliseconds. Defaults to `10_000`. ## Example config %CodeNameRaven.Monitor.Config{ id: "old-api-gone", name: "Old API Decommissioned", module: Integrations.HttpAbsent, params: %{url: "https://old-api.example.com"}, interval_ms: 300_000, enabled: true, tags: ["infra"] } ## Health signal * `:up` — Connection failed or timed out (site is unreachable — expected) * `:down` — Site responded with any HTTP status (site is reachable — unexpected) """ use CodeNameRaven.Monitor @default_timeout_ms 10_000 @impl true def params_template, do: %{url: "https://"} @impl true def params_schema do [ url: [type: :string, required: true, doc: "URL that should be unreachable (healthy when 4xx/5xx or no response)"], timeout_ms: [type: :non_neg_integer, default: 10_000, doc: "Request timeout in milliseconds"] ] end @impl true def target_uri(%{url: url}) when is_binary(url), do: {:ok, url} def target_uri(_params), do: :none @impl true def collect(%{url: _} = params, state), do: do_collect(params, state) def collect(params, state), do: {:error, "missing required param :url — got: #{inspect(params)}", state} defp do_collect(%{url: url} = params, state) do timeout_ms = Map.get(params, :timeout_ms, @default_timeout_ms) result = case Req.get(url, receive_timeout: timeout_ms, max_retries: 1) do {:ok, %{status: code}} -> %{url: url, reachable: true, status_code: code} {:error, _reason} -> %{url: url, reachable: false, status_code: nil} end {:ok, result, state} end @impl true def healthy?(%{reachable: false}), do: :up def healthy?(%{reachable: true}), do: :down end