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

Calls a function again when it fails.

A retry is declared in a module that uses `Rexsilient`:

    defmodule MyApp.Resilience do
      use Rexsilient

      alias Rexsilient.Retry.Strategy

      retry :payments do
        attempts 4
        strategy Strategy.Exponential, base_delay: 100, max_delay: 5_000, jitter: :full
      end
    end

and used with `@retry :payments` from `Rexsilient.Decorator`:

    defmodule MyApp.Payments do
      use Rexsilient.Decorator

      @retry :payments
      def charge(order) do
        PaymentsClient.charge(order)
      end
    end

or, without a decorator, with `run/2`:

    Rexsilient.Retry.run(:payments, fn -> PaymentsClient.charge(order) end)

## Settings

  * `attempts` - the total number of calls, the first one included. A
    positive integer, or `:infinity` to leave the limit to the strategy.
    Required.

  * `strategy` - the module that decides how long to wait before the next
    attempt, or to stop, and its options. Required. See
    `Rexsilient.Retry.Strategy`.

  * `classify_with` - the name of the functions, in the declaring module,
    that decide which outcomes are failures and so are retried. Defaults to
    `classify`; see `Rexsilient.Classify`.

## Behaviour

The function is called. If its outcome is a success, it is returned. If it
is a failure and attempts remain, the strategy is asked for a delay, the
caller sleeps for it, and the function is called again.

When no attempts remain, or the strategy stops, the last outcome is
returned unchanged: the value the function returned, or what it raised,
threw or exited with, re-raised with its original stacktrace.

`{:error, :circuit_open}` is never retried: a circuit breaker just said the
dependency is down, and retrying would only wait for the same answer. It is
a failure whatever `classify` says, and it ends the run at once.

The delay runs in the calling process, with `Process.sleep/1`.

> #### What is retried by default {: .warning}
>
> The default `classify` counts every `{:error, _}` and every raise, throw
> and exit as a failure, so all of them are retried. That includes bugs,
> such as a `FunctionClauseError`, which then crash only after every
> attempt and its delay. It also includes calls that are not idempotent
> and may have taken effect before failing. Use `classify_with` to retry
> only the failures that are safe and worth retrying.

# `name`

```elixir
@type name() :: atom()
```

The name a retry is declared with.

# `run`

```elixir
@spec run(name(), func :: (-&gt; term())) :: term()
```

Calls `func` through the retry `name`.

Returns the outcome of the last attempt; see [Behaviour](#module-behaviour).

Raises `ArgumentError` if no retry is registered under `name`.

## Examples

    Rexsilient.Retry.run(:payments, fn -> Payments.charge(order) end)

---

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