# `HTTP.ManagedTransport`
[🔗](https://github.com/gsmlg-dev/http_fetch/blob/v0.21.18/apps/http_runtime/lib/http/managed_transport.ex#L1)

Owns one bounded transport generation for a fixed origin and literal address.

`open/1` freezes direct TCP/TLS policy and creates private connection pools.
Pass the opaque scope as `transport_scope` to raw, streamed Fetch requests with
manual/error redirects. Request and connection capacity fail immediately;
request leases last through unread response streams.

`retire/2` closes admission and idle connections. Graceful retirement permits
admitted requests to finish; abort retirement also cancels them. Its durable
receipt can be awaited repeatedly from any process. `:ok` proves termination
of this generation's independently monitored requests, connectors, raw socket
ports, owners, private pools, supervisor and coordinator. A finite wait can
return `:cleanup_pending`; lost evidence returns `:cleanup_unconfirmed`.
Creator death initiates abort retirement. No request is replayed.
Success is logical resource retirement, not a certificate of native/deferred
timer, monitor, alias or signal-buffer reclamation, allocator/OS memory return,
or a numerical native-memory budget. Missing or mismatched native accounting
certification cannot be replaced by a snapshot or retirement receipt.

## Opening and selecting a generation

    {:ok, scope} = HTTP.ManagedTransport.open(
      origin: "https://upstream.example",
      connect_address: {192, 0, 2, 10},
      http_version: :http2,
      max_requests: 100,
      max_connections: 2,
      idle_timeout: 30_000
    )

    promise = HTTP.fetch("https://upstream.example/data",
      transport_scope: scope,
      redirect: :manual,
      decode_body: false,
      stream_response: true
    )

`origin`, literal `connect_address` and explicit `http_version` are required.
Supported protocols are `:http1` (HTTP/HTTPS), `:http2` (HTTPS) and `:h2c`
(HTTP). Optional capacity is `max_requests: 1..2048` (default 100),
`max_connections: 1..256` (default 2), `max_pending: 0`, and
`idle_timeout: 1..60000` milliseconds (default 30000). `ssl` and `socket_opts`
freeze supported TLS/socket settings. `tls_backend: :ssl` (the current default)
and explicit `:ex_ssl` support HTTPS H1/H2; only `http2_profile: :native_v1`
is accepted. TLS files and system CAs are captured
once at open; rotated policy requires a new scope. For explicit HTTPS `:http1`,
`ssl: [alpn_advertised_protocols: ["http/1.1"]]` optionally advertises the single
fixed binary protocol. Omitting it preserves no ALPN advertisement. Other
ALPN lists, server ALPN settings and explicit ALPN overrides for managed H2
are rejected; H2 retains its protocol-selected `"h2"` advertisement. See the
managed transport guide for the supported SSL option keys.

Request capacity includes preparation and unread streams. Connections include
connecting, checked-out and idle transports. Exhaustion returns
`{:error, {:transport_scope_capacity, :requests | :connections}}`, with no
waiting queue. Frozen TLS/socket policy owns compact binary backing within its
1 MiB serialized limit. Freeze/preparation copy overlap and OTP's parsed TLS
state are outside that retained-policy payload bound. Request metadata is
bounded to 64 KiB/256 fields,
buffered upload bodies to 1 MiB, and upload chunks/bridges to 64 KiB. The native
HTTP/2 writer/receive budgets are 1 MiB each per connection, header blocks are
bounded to 64 KiB/256 fields/256 frames. The H2 owner admits at most 128
informational heads/64 KiB regular metadata over each request lifetime, before
enqueueing. Each request generates at most 130 header notifications including
final headers/trailers. SETTINGS pool snapshots coalesce with one in flight;
GOAWAY draining notices are one-shot. See the managed transport guide for
accounted-data, representation and decode/copy overlap reservations.
Caller-owned producer input, arbitrary
public-operation messages, OS/TLS allocations and the whole VM are outside
these retained transport bounds.

Conflicting origin, route, TLS or socket overrides fail before dialing. Each
request/connect deadline remains independent; socket writer settings stay
frozen. Managed upload attachment and admission use the request deadline.
An unresponsive caller source receives cooperative stop but keeps cleanup
pending and its slot occupied until the caller terminates it.

## Status and retirement

    {:ok, status} = HTTP.ManagedTransport.snapshot(scope, 100)
    {:ok, receipt} = HTTP.ManagedTransport.retire(scope, mode: :graceful)
    :ok = HTTP.ManagedTransport.await_retired(receipt, 1_000)

Snapshot and receipt waits require finite, nonnegative millisecond timeouts.
Snapshots contain aggregate counts, finite limits, policy digest and lifecycle,
without request history or credentials. Retirement closes admission and idle
sockets immediately; `:graceful` drains live requests, while `:abort` requests
cancellation. Neither a response terminal event nor an individual
`HTTP.RequestCompletion` proves whole-generation retirement. A caller may retry
receipt waits after `{:error, :cleanup_pending}`. Lost evidence produces
`{:error, :cleanup_unconfirmed}`. Normal coordinator termination preserves the
durable receipt; unexpected coordinator death cannot report success.

OTP TLS connections retain independent receiver and sender termination
evidence after pool handoff. If TLS setup fails without returning a socket,
or its resource representation is unsupported, the generation retires with
unconfirmed cleanup; open a new scope for subsequent requests.

# `t`

```elixir
@opaque t()
```

# `await_retired`

```elixir
@spec await_retired(HTTP.ManagedTransport.Receipt.t(), non_neg_integer()) ::
  :ok | {:error, term()}
```

# `open`

```elixir
@spec open(keyword()) :: {:ok, t()} | {:error, term()}
```

# `retire`

```elixir
@spec retire(t(), keyword()) ::
  {:ok, HTTP.ManagedTransport.Receipt.t()} | {:error, term()}
```

# `snapshot`

```elixir
@spec snapshot(t(), non_neg_integer()) :: {:ok, map()} | {:error, term()}
```

---

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