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

Replaces the outcome of a failed call with the result of another function.

A fallback is declared in a module that uses `Rexsilient`, with the function
to call instead:

    defmodule MyApp.Resilience do
      use Rexsilient

      fallback :prices do
        function :cached_price
      end

      def cached_price(sku), do: Cache.last_price(sku)
    end

and used with `@fallback :prices` from `Rexsilient.Decorator`, which calls
the fallback function with the decorated function's arguments:

    defmodule MyApp.Prices do
      use Rexsilient.Decorator

      @fallback :prices
      def fetch(sku) do
        PricesClient.fetch(sku)
      end
    end

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

    Rexsilient.Fallback.run(:prices, fn sku -> PricesClient.fetch(sku) end, sku)

## Settings

  * `function` - the function called on failure: a name, for a function in
    the declaring module, or `{module, name}` for one in another module.
    Required.

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

## Behaviour

The call is made. If its outcome is a success, it is returned unchanged.
If it is a failure, the fallback function is called with the same
arguments, and its result is returned instead; a raise, throw or exit
counted as a failure is not re-raised.

`{:error, :circuit_open}` is always replaced, without asking the classifier:
a circuit breaker rejected the call, so there is no result to keep. This
lets a fallback declared around a breaker answer while the breaker is open.

An error raised by the fallback function itself propagates to the caller.

# `name`

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

The name a fallback is declared with.

# `run`

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

Calls `func` with `args` through the fallback `name`.

`args` is passed to `func` as its only argument, and to the fallback
function in the same way, so both take one argument. Use a list or a tuple
to pass several values. Returns `func`'s result, or the fallback's on
failure; see [Behaviour](#module-behaviour).

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

## Examples

    Rexsilient.Fallback.run(:prices, fn sku -> Prices.fetch(sku) end, sku)

---

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