# `ExternalService.ServiceSaturated`
[🔗](https://github.com/jvoegele/external_service/blob/main/lib/external_service/errors.ex#L85)

Raised or returned when a call could not be made because the service's
concurrency limit was already fully in use.

This is an [Errata](https://hexdocs.pm/errata) infrastructure error. The same
value is returned in an `{:error, error}` tuple by `ExternalService.call/3` and
raised by `ExternalService.call!/3`.

Its `:context` contains:

  * `:service` — the service the call was made against.
  * `:limit` — the configured concurrency limit.
  * `:in_flight` — how many slots were held when the call was rejected.

Only services configured with a `:concurrency` limit can produce this error.
Its `http_status/1` is the default `503`: unlike `ExternalService.RateLimited`,
this is not the external service refusing you, it is your own bulkhead shedding
load — a "Service Unavailable" from your application.

Because the wrapped function never ran, this does *not* melt the circuit
breaker and is not retried. Retrying immediately would only find the bulkhead
full again; shedding is the point. See `ExternalService.Concurrency`.

Like `ExternalService.RateLimited`, it is still retryable in Errata's sense —
the call is worth making again once in-flight calls drain — just not on the
spot.

# `t`

```elixir
@type t() :: Errata.infrastructure_error()
```

# `code`

```elixir
@spec code(Errata.error()) :: String.t() | nil
```

Returns the stable external code for this error, or `nil` if it has none.

No code is set for this error type. Set one with the `:code` option, or
override this function to derive a code from the error's `:reason` or
`:context`. See also `Errata.code/1`.

# `display_message`

```elixir
@spec display_message(Errata.error()) :: String.t() | nil
```

Returns the user-facing _display message_ for this error (the `:message` field by default).

This is distinct from `Exception.message/1`, which also includes the error's `:reason` and is
aimed at developers. Override this function to compute a message from the error's `:reason` or
`:context`:

    def display_message(%{context: %{order_id: id}}), do: "order #{id} does not exist"
    def display_message(error), do: error.message

`Errata.display_message/1` and `Errata.to_map/1` both dispatch through this function, so an
override applies to the JSON encoding and to anything rendering the error for a user. See also
`Errata.display_message/1`.

# `http_status`

```elixir
@spec http_status(Errata.error()) :: non_neg_integer()
```

Returns the HTTP status code associated with this error (`503` by default).

The default is derived from the error's kind, or set via the `:http_status`
option. Override this function to compute a status from the error's `:reason`
or `:context`. See also `Errata.http_status/1`.

# `redact_context`

```elixir
@spec redact_context(Errata.error()) :: map()
```

Returns this error's `:context` with sensitive values redacted (no keys declared).

Called wherever Errata serializes the context — `to_map/1` and the JSON
encoding, `Errata.log/2` metadata, and `Errata.report/2` telemetry metadata.
The error struct itself is left alone, so the real values remain available
locally for debugging.

Declared keys are redacted recursively and match whether written as atoms or
binaries. Set them with the `:redact` option, add a global floor with
`config :errata, redact: [...]`, or override this function for full control.
See `Errata.Redaction`.

# `retryable?`

```elixir
@spec retryable?(Errata.error()) :: boolean()
```

Returns whether this error is considered retryable (`true` by default).

The default is derived from the error's kind — `:infrastructure` errors are
retryable, `:domain` and `:general` errors are not — or set via the
`:retryable` option. Override this function to decide from the error's
`:reason` or `:context`. See also `Errata.retryable?/1`.

# `severity`

```elixir
@spec severity(Errata.error()) :: Logger.level()
```

Returns the severity of this error (`:error` by default).

The severity is a `t:Logger.level/0` and is the level at which `Errata.log/2`
logs the error when no level is given explicitly. Set it with the `:severity`
option, or override this function to compute a severity from the error's
`:reason` or `:context`. See also `Errata.severity/1`.

---

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