fettle v1.0.0 Fettle.Checker behaviour View Source
The behaviour to be implemented by healthcheck modules.
The check/1 function should return either a Fettle.Checker.Result, or a tuple
with Fettle.Checker.Result as the first element, and the second element some state
to maintain for the next run. An optional init/1 function can set up an initial
state based on config.
Stateless checker modules
Without an init/1 function, the check/1 module will receive the value of the args
option from the check configuration, and should return a Fettle.Checker.Result depending
on the result of running its check:
e.g. assuming this configuration:
config :fettle,
...
checks: [
[
name: "check name",
...
checker: MySimpleChecker,
args: [a: 1, b: 2] # will be supplied as argument to check/1
],
...
]
}
If the MySimpleChecker module is defined thus:
defmodule MySimpleChecker do
use Fettle.Checker # convenience to get Result import and @behaviour
def check(args) do
%Result{} = do_some_check(args[:a], args[:b])
end
end
the module will be called each time with the value of args from config, and will
return a Fettle.Checker.Result corresponding to the check result.
In addition, an init/1 function may be defined to transform the args state
for the check/1 function.
Stateful checkers
Checker modules may optionally maintain state between calls, allowing them to perform flap detection or other functionality.
If the init/1 function is implemented, it will receive the argument configured
using the args key in the check config; the function can then return the
initial state to be passed to the check/1 function. The check/1 function can
update this state and return it along with the Fettle.Checker.Result.
e.g. assuming configuration:
config :fettle,
...
checks: [
[
name: "check name",
...
checker: NStrikesChecker,
args: [a: 1, b: 2, limit: 3]
],
...
]
}
We could implement a module that required n failures before reporting an error state, by maintaining the number of consecutive failures thus:
defmodule NStrikesChecker do
use Fettle.Checker
def init(args) do
Enum.into(Keyword.merge([limit: 3], args), %{failure_count: 0})
end
def check(state = %{a: a, b: b, limit: limit, failure_count: failure_count}) do
result = %Result{status: status} = do_some_check(a, b)
case {status, failure_count + 1} do
{:ok, _} ->
{result, %{state | failure_count: 0}}
{_status, count} where count >= limit ->
{result, %{state | failure_count: count}}
{_status, count} ->
{Result.ok(), %{state | failure_count: count}}
end
end
end
The NStrikesChecker module will be initialized using:
state1 = NStrikesChecker.init(a: 1, b: 2, limit: 3)
and then scheduled to be called with the state state1 to actually perform the check:
{result = %Result{}, state2} = NStrikesChecker.check(state1)
the check returns a tuple with the %Fettle.Checker.Result{} and the updated state,
ready for the next check run.
In any case, the
init/1function is optional, and thecheck/1function can return either a simpleResultor a{Result, state}tuple. Just take care you know what’s going on with your state!
Timeouts
Note that checks must complete within the timeout period (timeout_ms) configured for
the check (or globally in top-level config), or else they will be terminated (:killed)
and will be set with a result of :error.
Link to this section Summary
Link to this section Callbacks
check(state :: any()) :: {Fettle.Checker.Result.t(), state :: any()} | Fettle.Checker.Result.t()