# `Apero.Retry`
[🔗](https://github.com/Lorenzo-SF/apero/blob/3.0.0/lib/apero/retry.ex#L1)

Retry with exponential backoff and optional jitter.

## Example

    Apero.Retry.with(
      fn -> HTTPoison.get(url) end,
      max_attempts: 5,
      base_delay: 100,
      max_delay: 5_000,
      retry_on: fn
        {:ok, %{status: status}} when status >= 500 -> true
        {:error, %HTTPoison.Error{reason: :timeout}} -> true
        _ -> false
      end
    )

# `predicate`

```elixir
@type predicate() :: (any() -&gt; boolean())
```

# `handle_message`

```elixir
@spec handle_message(
  {:apero_retry, (-&gt; any()), integer(), integer(), integer(), integer(),
   (any() -&gt; boolean()), (-&gt; any())}
) :: any()
```

Handles a `{:apero_retry, ...}` message produced by `schedule_next/7`.
Runs the next attempt; if it succeeds or exhausts retries, returns the
result via `{:apero_retry_done, result}`. Otherwise schedules the
next retry.

This is the GenServer hook for non-blocking retry.

# `schedule_next`

```elixir
@spec schedule_next(
  (-&gt; any()),
  integer(),
  integer(),
  integer(),
  integer(),
  (any() -&gt; boolean()),
  (-&gt; any())
) :: :ok
```

Non-blocking variant of `with/2` that uses `Process.send_after` between
attempts instead of `Process.sleep`.

## Caveats

Because the retry is driven by the calling process's mailbox, this
helper must be called from a process that can receive messages
(typically a GenServer). The calling process should be ready to
receive the `{:apero_retry_continue, fun, state}` message; in practice
this helper is best used from a custom `handle_info/2` that calls
the next attempt and sends itself another message after the delay.

Most consumers should prefer the simpler `with/2` (which uses
`Process.sleep`) unless they are calling from a GenServer mailbox
loop.

# `with`

```elixir
@spec with(
  (-&gt; any()),
  keyword()
) :: any()
```

---

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