# `Redis.Connection`
[🔗](https://github.com/joshrotenberg/redis_ex/blob/v0.7.1/lib/redis/connection/connection.ex#L1)

GenServer managing a single TCP/TLS connection to a Redis server.

Handles the socket lifecycle, RESP3 handshake, command sending/receiving,
pipeline buffering, and automatic reconnection with exponential backoff.

## Options

  * `:host` - Redis host (default: "127.0.0.1")
  * `:port` - Redis port (default: 6379)
  * `:password` - auth password (string or `{mod, fun, args}` MFA tuple)
  * `:username` - auth username (Redis 6+ ACL)
  * `:database` - database number to SELECT
  * `:ssl` - enable TLS (default: false)
  * `:ssl_opts` - SSL options list
  * `:socket` - Unix domain socket path (overrides host/port)
  * `:name` - GenServer name registration
  * `:sync_connect` - connect synchronously in init (default: true)
  * `:backoff_initial` - initial reconnect delay ms (default: 500)
  * `:backoff_max` - max reconnect delay ms (default: 30_000)
  * `:protocol` - `:resp3` or `:resp2` (default: `:resp3`)
  * `:client_name` - CLIENT SETNAME value
  * `:timeout` - command timeout ms (default: 5_000)
  * `:credential_provider` - `{module, opts}` implementing `Redis.CredentialProvider`
    for dynamic/rotating credentials (e.g., cloud IAM tokens).
    When set, `:password` and `:username` are ignored.
  * `:exit_on_disconnection` - exit instead of reconnecting (default: false)
  * `:hibernate_after` - idle ms before hibernation (default: nil)
  * `:hooks` - list of `Redis.Hook` modules for command middleware (default: [])

A Redis URI string may be passed as the first (sole) argument:

    Connection.start_link("redis://:secret@localhost:6380/2")

# `child_spec`

Returns a child spec for supervision trees.

    children = [
      {Redis.Connection, port: 6379, name: :redis}
    ]

# `noreply_command`

```elixir
@spec noreply_command(GenServer.server(), [String.t()], keyword()) ::
  :ok | {:error, term()}
```

Sends a command without waiting for a reply.
Uses CLIENT REPLY OFF/ON internally.

# `noreply_pipeline`

```elixir
@spec noreply_pipeline(GenServer.server(), [[String.t()]], keyword()) ::
  :ok | {:error, term()}
```

Sends multiple commands without waiting for replies.

# `start_link`

# `start_link`

```elixir
@spec start_link(keyword() | String.t()) :: GenServer.on_start()
```

# `watch_transaction`

```elixir
@spec watch_transaction(
  GenServer.server(),
  [String.t()],
  (GenServer.server() -&gt; [[String.t()]] | {:abort, term()}),
  keyword()
) :: {:ok, [term()]} | {:error, term()}
```

Executes a WATCH-based optimistic locking transaction.

Watches the given keys, calls `fun` with the connection to read current
values and compute commands, then executes those commands in a MULTI/EXEC
block. If any watched key was modified by another client, EXEC returns nil
and the function is retried (up to `:max_retries` times, default 3).

The function `fun` receives the connection and must return either:
- a list of commands to execute in the transaction
- `{:abort, reason}` to abort without executing

Returns `{:ok, results}` on success, `{:error, :watch_conflict}` if all
retries are exhausted, or `{:error, reason}` on other failures.

## Example

    Redis.Connection.watch_transaction(conn, ["account:1", "account:2"], fn conn ->
      {:ok, bal1} = Redis.Connection.command(conn, ["GET", "account:1"])
      {:ok, bal2} = Redis.Connection.command(conn, ["GET", "account:2"])

      amount = 100
      new1 = String.to_integer(bal1) - amount
      new2 = String.to_integer(bal2) + amount

      [
        ["SET", "account:1", to_string(new1)],
        ["SET", "account:2", to_string(new2)]
      ]
    end)

---

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