# `Arangox.Connection`
[🔗](https://github.com/ArangoDB-Community/arangox/blob/v0.8.0/lib/arangox/connection.ex#L1)

`DBConnection` implementation for `Arangox`.

## The connect pipeline

`connect/1` walks the configured endpoints in order and runs one linear
pipeline per endpoint:

    resolve options -> open (do_connect) -> resolve_auth
      -> check_availability -> discover_version -> ready

Everything after `do_connect` owns an open socket, so every exit from those
stages other than a successful return closes that socket first. Failing to
do so leaks a socket per attempt, not per process: `DBConnection` retries
`connect/1` *in the same process* under backoff, so the leaked sockets pile
up in a live process instead of dying with it.

`check_availability` has a fourth outcome besides ok/next/error: a `503`
naming the current leader in `x-arango-endpoint` re-enters the walk at that
leader, once the redirect admission policy has admitted it. See the comments
above `redirect/3` for the policy and `Arangox.start_link/1` for the
user-facing rules and the `:endpoint_mapper` trust boundary.

No stage raises. Endpoint parsing goes through `Arangox.Endpoint.parse/1`
and response bodies are decoded with a non-raising decoder, because a raise
here escapes the `DBConnection` callback and turns an orderly backoff into a
supervisor crash loop.

## Credentials never reach state, an error or a log

`new/4` stores `Arangox.Endpoint.redact/1` of the configured endpoint, not the
configured endpoint. That single substitution covers three exits at once: the
`:endpoint` field of every `Arangox.Error` built here, `Exception.message/1`
(which prepends `[endpoint] `), and the `failed to connect` line
`DBConnection` logs on every backoff cycle.

Redacting only at render would have left `inspect(state)` leaking, and
`DBConnection`'s own `:show_sensitive_data_on_connection_error` does not help:
it sanitizes only exceptions that **escape** `connect/1`, and this
module never lets one escape — it returns `{:error, exception}`, which
`DBConnection` logs unsanitized. There is no opt-out, so the redaction is
unconditional and there is no option to turn it off.

`:auth` and the resolved `authorization` header still hold the credential in
state, because the request path needs them; the `Inspect` implementation at
the bottom of this file redacts both.

## Cost of the walk

The walk is per connect *attempt*, and a connect attempt is retried on the
usual `:backoff_min`/`:backoff_max` schedule for as long as the pool lives.
With N endpoints that are all down, every backoff cycle of every pool process
costs N connection attempts, N `:failover_callback` invocations and one
`failed to connect` log line. A pool of 10 against 3 dead endpoints at the
default one-second minimum backoff is therefore ~30 connection attempts and
~30 callback invocations per second. Keep `:failover_callback` cheap and
non-blocking, and raise `:backoff_min` if the log volume matters.

# `failover?`

```elixir
@type failover?() :: boolean()
```

# `t`

```elixir
@type t() :: %Arangox.Connection{
  auth: Arangox.Auth.t(),
  client: module(),
  content_type: :json | :velocypack,
  cursors: map(),
  database: binary(),
  disconnect_on_error_codes: [integer()],
  endpoint: Arangox.endpoint(),
  failover?: boolean(),
  headers: Arangox.headers(),
  json_library: module(),
  max_body_size: pos_integer(),
  parsed_endpoint: Arangox.Endpoint.t() | nil,
  read_only?: boolean(),
  request_timeout: pos_integer() | nil,
  server_version: Version.t() | nil,
  socket: any(),
  trx_id: binary() | nil,
  vst_maxsize: pos_integer()
}
```

---

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