# `Rexsilient.Notifier`
[🔗](https://github.com/fabiobarkoski/rexsilient/blob/v1.0.0/lib/rexsilient/notifier.ex#L1)

Tells notifiers what the patterns are doing.

A notifier is a module that implements this behaviour, listed in the
`:notifiers` option of `Rexsilient`:

    defmodule MyApp.Notifier do
      @behaviour Rexsilient.Notifier

      require Logger

      @impl true
      def notify(:after, :retry, %{result: :failure} = state) do
        Logger.warning("retry #{inspect(state.name)}: attempt #{state.attempt} failed")
      end

      def notify(_moment, _kind, _state), do: :ok
    end

    children = [
      {Rexsilient, modules: [MyApp.Resilience], notifiers: [MyApp.Notifier]}
    ]

Every notifier gets every notification; match on `kind` and the `:name` in
`state` to keep only the ones needed. Without notifiers, nothing is sent.

## Moments

`kind` is the pattern, and `state` a map that always has its `:name`.

Every `:before` also has `:monotonic_time` and `:system_time`, and every
`:after` has `:monotonic_time` and the `:duration` since its `:before`, all
in native time units, measured in the calling process.

`:circuit_breaker`, around calls made with `Rexsilient.CircuitBreaker.run/3`:

  * `:before` - an allowed call is about to run.

  * `:after` - it finished, with its `:result` and `:outcome`.

  * `:rejected` - the breaker rejected the call, with its `:system_time`.

Calls made with `Rexsilient.CircuitBreaker.acquire/1` and
`Rexsilient.CircuitBreaker.release/4` directly send none of these.

`:circuit_breaker`, when the breaker changes state, with the state it was
in as `:from`, and the `:system_time` at which the change happened:

  * `:open` - it opened, with the `:timeout` before it becomes half-open,
    and the `:outcome` that opened it. When forced with
    `Rexsilient.CircuitBreaker.force_open/1`, `:timeout` is `:infinity`
    and `:outcome` is `nil`.

  * `:half_open` - it lets the next call through as a probe.

  * `:probing` - a probe started, with the `:timeout` before another one
    is let through.

  * `:closed` - a probe succeeded, it was forced closed, or the breaker
    manager restarted while it was not closed.

A change made with `Rexsilient.CircuitBreaker.force_open/1` or
`Rexsilient.CircuitBreaker.force_close/1` also has `forced: true`, and
one made by a manager restart has `restart: true`.

`:retry`:

  * `:before` - an attempt is about to run, with its `:attempt` number.

  * `:after` - it finished, with its `:attempt`, `:result` and `:outcome`.

  * `:delay` - it failed and the next attempt waits `:delay` milliseconds,
    with its `:attempt` and `:outcome`.

  * `:stop` - it failed and no attempt follows, with its `:attempt`,
    `:outcome`, the `:duration` of the whole run, and the `:reason`:
    `:attempts` when none remain, `:strategy` when the strategy stopped,
    `:circuit_open` when the attempt returned `{:error, :circuit_open}`.

`:fallback`, only when the fallback function is called:

  * `:before` - it is about to run, with the `:outcome` it replaces.

  * `:after` - it returned, with its `:outcome`.

`:result` is `:success` or `:failure`, as classified, and `:outcome` is a
`t:Rexsilient.Classify.outcome/0`. More moments and keys may be added, so
end with a catch-all clause.

State changes are notified from both the calling processes and the breaker
manager, so they may arrive out of order; use `:system_time` to order them.

## Process

Notifications are sent to a single notifier process, started by
`Rexsilient`. The call being notified does not wait for it, so `:before`
is handled after the call has started.

For each notification, every notifier is called in its own task, and the
next notification waits for all of them, so each notifier sees them in the
order the notifier process received them. A notifier that raises or exits
only crashes its own task, which logs the error; one that takes longer than
5 seconds is killed, and the timeout is logged. Either way it is skipped for that notification, and
the others are not affected.

> #### The notifier mailbox has no limit {: .warning}
>
> Notifications wait in the notifier process's mailbox, which has no limit.
> When they arrive faster than the notifiers handle them, for example with a
> notifier that takes a few milliseconds under high traffic, they arrive
> later and later, and the mailbox, and so memory, keeps growing.

`Rexsilient.Notifier.TelemetryNotifier`, the default, is the exception: it
is called in the calling process, like any `:telemetry` event, so its
handlers see the caller's context. Notifications sent by the breaker
manager still go through the notifier process, so the manager never runs
handlers.

# `kind`

```elixir
@type kind() :: :circuit_breaker | :fallback | :retry
```

The pattern that sends it.

# `moment`

```elixir
@type moment() ::
  :before
  | :after
  | :rejected
  | :open
  | :half_open
  | :probing
  | :closed
  | :delay
  | :stop
```

When the notification is sent; see [Moments](#module-moments).

# `notify`

```elixir
@callback notify(moment(), kind(), state :: map()) :: term()
```

Called, in a task, for every notification; see [Process](#module-process).

The return value is ignored.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
