CodeNameRaven. Handler behaviour
(raven_observer_sdk v0.6.0)
Copy Markdown
The behaviour contract for a Raven alert handler.
A handler watches the DataBus for monitor status events and decides when to fire. When it fires, the platform calls every channel in the handler's config. Handlers run as supervised GenServer processes — one process per configured handler instance — giving them persistent state across events.
This is the last piece of the alerting stack:
Monitor → DataBus → Handler → ChannelMonitors publish health signals. Handlers react to those signals. Channels deliver the notification.
Implementing a handler
defmodule MyHandlers.OnDown do
use CodeNameRaven.Handler
@impl true
def handler_init(_params), do: {:ok, %{}}
@impl true
def on_status(%{status: :down} = msg, _params, state) do
notification = %Notification{
monitor_id: msg.monitor_id,
status: :down,
previous_status: nil,
occurred_at: msg.checked_at
}
{:fire, notification, state}
end
def on_status(_msg, _params, state), do: {:ok, state}
endon_status/3 is the only required callback — everything else has a working
default.
Return values from on_status/3
{:ok, new_state}— no alert; update state and wait for the next event.{:fire, notification, new_state}— delivernotificationto every channel in this handler's config, then update state.
The status argument
on_status/3's first argument is loosely typed (term()) rather than a
concrete struct — the real message module (and its version/upcast
machinery) lives in Raven itself, not this SDK, matching
CodeNameRaven.Probe.on_metric/3's precedent for the identical problem.
It has (at least) these fields: monitor_id (string), status
(:up | :degraded | :down | :unknown), checked_at (DateTime.t()),
node (the reporting node, or nil/:nonode@nohost for a local-only
signal). Raven upcasts the message to its current version before this
callback ever sees it, so implementations never need to think about
version compatibility themselves — pattern-match on the fields you need
with a plain map pattern (it matches the real struct too, since structs
are maps) rather than a named struct.
State
handler_state is opaque to the platform. Use it to track whatever the
handler needs between events: the last known status per monitor, cooldown
timers, deduplication keys. The state is ephemeral — a handler restart
resets it via handler_init/1.
Summary
Callbacks
Returns the category this handler belongs to.
Returns the human-readable name for this handler type.
Initialises the handler's state.
Reacts to a monitor status event.
Called periodically to perform timed tasks, such as checking for stale monitors.
Returns the NimbleOptions-style schema for validating/rendering this
handler's params — the type-aware form the admin UI renders (checkbox
for booleans, dropdown for a fixed set of choices) instead of a generic
text box. Defaults to [] (no schema, fully backward compatible with
every handler predating this callback — the UI falls back to
params_template/0 in that case).
Returns a template map of params this handler expects.
Functions
Returns true if the given module implements the Handler behaviour.
Callbacks
@callback category() :: atom()
Returns the category this handler belongs to.
@callback display_name() :: String.t()
Returns the human-readable name for this handler type.
Initialises the handler's state.
Called once when the handler process starts. Returns {:ok, initial_state}
on success or {:error, reason} if the handler cannot start.
The default implementation returns {:ok, %{}}.
@callback on_status( status :: term(), params :: map(), state :: term() ) :: {:ok, term()} | {:fire, CodeNameRaven.Channel.Notification.t(), term()}
Reacts to a monitor status event.
Called for every status event published to the DataBus — see "The status
argument" above for its shape. Return {:ok, new_state} to update state
without firing, or {:fire, notification, new_state} to trigger channel
delivery.
The default implementation ignores all events and returns {:ok, state}.
@callback on_tick( params :: map(), state :: term() ) :: {:ok, term()} | {:fire, CodeNameRaven.Channel.Notification.t() | [CodeNameRaven.Channel.Notification.t()], term()}
Called periodically to perform timed tasks, such as checking for stale monitors.
@callback params_schema() :: keyword()
Returns the NimbleOptions-style schema for validating/rendering this
handler's params — the type-aware form the admin UI renders (checkbox
for booleans, dropdown for a fixed set of choices) instead of a generic
text box. Defaults to [] (no schema, fully backward compatible with
every handler predating this callback — the UI falls back to
params_template/0 in that case).
@callback params_template() :: map()
Returns a template map of params this handler expects.
Used by the admin UI as a fallback to derive a configuration form when
params_schema/0 is empty.