1 Connection Lifecycle
spotdemo4 edited this page 2026-07-11 11:35:52 -04:00

Connection Lifecycle

Every TrevRPC runtime exposes a long-lived application Channel or RpcChannel. Reconnection is part of the channel contract, not an optional wrapper or feature flag. Applications create one channel, share it across generated clients, and close it during shutdown.

Raw transports that own exactly one connection or WebTransport session are advanced-only. They exist for integrations, benchmarks, diagnostics, and deterministic transport tests, not routine application use.

Call Contract

Each ready connection is a generation. A new unary or streaming RPC snapshots exactly one ready generation when it starts.

  • The RPC remains attached to that generation for its entire lifetime.
  • If the generation dies, every in-flight RPC on it fails through the runtime's normal transport error path.
  • TrevRPC never retries, replays, resumes, or moves a call to a later generation.
  • The channel reconnects in the background for future calls.
  • A new call made while the channel is connecting or reconnecting fails immediately with Unavailable or the runtime's equivalent.
  • Applications call the runtime readiness API before issuing work when waiting is intentional.
  • A remote RPC Unavailable status never authorizes reconnecting or replaying that RPC.
  • Explicit channel close is terminal and stops reconnection.

Applications own RPC retry policy. This keeps idempotency, duplicate side effects, and request replay decisions above the connection lifecycle.

Routine APIs

Runtime Application API Coverage Readiness
Rust trevrpc::client::Channel::connect Native Quinn QUIC wait_until_ready
Rust trevrpc::client::Channel::connect_webtransport WebTransport wait_until_ready
Go trevrpc.Dial(ctx, target, trevrpc.DialOptions) returning *trevrpc.Channel Address targets use native QUIC; https:// targets use WebTransport WaitUntilReady
C trevrpc_channel_connect returning trevrpc_channel* Native MsQuic QUIC trevrpc_channel_wait_ready
Kotlin NettyRpcChannel.nativeQuic(config) returning RpcChannel Netty native QUIC awaitReady
Kotlin NettyRpcChannel.http3(config) returning RpcChannel Netty ordinary HTTP/3 awaitReady
Kotlin CronetRpcChannel.create(...) returning RpcChannel Provider-owned Cronet HTTP/3 awaitReady
Browser JavaScript connect(url, options) from trevrpc-js, returning Channel Browser WebTransport waitUntilReady
Node JavaScript Root connect(...) or Channel from trevrpc-js/node Native MsQuic waitUntilReady

Generated clients accept these channels directly. Generated C methods directly accept trevrpc_channel*; there are no separate channel-specific method variants.

Rust connect, Go Dial, C trevrpc_channel_connect, and JavaScript connect wait for the first ready generation; bound initial setup with the runtime's normal future, context, timeout, cancellation, or constructor option. Kotlin Netty factories return a channel whose initial state may still be connecting, so call awaitReady before initial work when waiting is intentional. After creation, calls fail fast during a reconnect unless application code explicitly waits for readiness.

Cronet owns its physical connection pool and reconnection behavior. CronetRpcChannel provides the same long-lived application surface, but TrevRPC does not claim control over Cronet's internal connection generations, path migration, or TLS ticket policy. TrevRPC still never retries or replays an RPC.

Reconnect Backoff

Every TrevRPC-controlled reconnect loop uses the same fixed reconnect defaults:

  • Initial delay: 100 ms.
  • Multiplier: 2.
  • Jitter: 20 percent.
  • Maximum delay: 30 seconds.

Backoff resets after a generation becomes ready. Routine constructors do not expose reconnect-policy tuning. Advanced and runtime-test paths may override it when deterministic timing or specialized integration behavior requires that control.

Lifecycle state and generation are observable where the runtime exposes them. Runtime event hooks may report connection loss, reconnect failure, readiness, and close. Keep callbacks non-blocking; bounded event queues may coalesce or drop detail for a persistently slow observer while the latest channel state remains authoritative.

Advanced APIs

Runtime Advanced API Purpose
Rust trevrpc::advanced::RawQuinnTransport One established Quinn connection
Rust trevrpc::advanced::RawWebTransport One established WebTransport session
Rust trevrpc::advanced::ChannelOperations Quinn endpoint address and rebind operations
Rust trevrpc::advanced::ChannelConfigOperations Reconnect-policy tuning for specialized and test paths
Rust trevrpc::advanced::connect_webtransport_channel_with_request Channel creation with a custom WebTransport CONNECT request
Go trevrpc.Advanced.NewRawQUICClient One caller-owned quic-go connection
Go trevrpc.Advanced.DialRawWebTransport Dial one WebTransport session
Go trevrpc.Advanced.NewRawWebTransportClient One caller-owned WebTransport session
Go trevrpc.Advanced.Channel(channel).AddPath Path operations on the current native QUIC generation
Go trevrpc.Advanced.Channel(channel).RawWebTransportSession Inspect the current WebTransport session
C trevrpc_raw_client APIs from trevrpc_raw.h Single-connection native QUIC and WebTransport operations
C trevrpc_channel_options_set_backoff from trevrpc_raw.h Advanced channel backoff tuning
Kotlin zip.trev.trevrpc.netty.advanced.RawNettyQuicRpcTransport One Netty native QUIC connection
Kotlin zip.trev.trevrpc.netty.advanced.RawNettyHttp3RpcTransport One Netty HTTP/3 connection
Browser JavaScript RawWebTransport from trevrpc-js/advanced One browser WebTransport session
Node JavaScript RawNodeTransport from trevrpc-js/node/advanced One native MsQuic connection

Raw transports do not reconnect. Code using one must own connection establishment, failure detection, and shutdown explicitly.

TLS Resumption And 0-RTT

TLS session resumption only optimizes a later connection handshake. It does not recover an RPC or application session, and it never changes generation pinning.

Where TrevRPC controls QUIC setup, 0-RTT application data remains disabled. A missing, expired, rejected, or incompatible resumption ticket falls back to a full handshake without changing RPC semantics. Browser, Cronet, and other provider-controlled stacks may retain internal TLS state, but TrevRPC does not expose that behavior as a correctness guarantee.

Path Migration

Path migration preserves a living QUIC connection; reconnection replaces a dead connection. A successful path change keeps the same generation and may preserve in-flight streams.

Runtime Migration behavior
Rust / Quinn Import trevrpc::advanced::ChannelOperations and call channel.rebind_quinn(socket). Quinn rebinding is endpoint-wide and affects every connection sharing that endpoint.
Go / quic-go Call trevrpc.Advanced.Channel(channel).AddPath(transport), then probe and switch the returned quic-go path.
C / MsQuic MsQuic handles supported migration and NAT rebinding; channel lifecycle events report address changes.
Browser WebTransport The browser owns path changes. JavaScript can observe channel state but cannot control QUIC paths.
Kotlin / Cronet Netty or Cronet owns path behavior; TrevRPC exposes no portable migration operation.

Migration depends on peer transport parameters, routing, NAT behavior, and load-balancer connection-ID support. A failed migration may eventually close the generation and enter normal channel reconnection.

Shutdown

Closing a channel stops future generations and closes its current connection. Existing runtime cancellation rules apply to calls still attached to that generation.

The C API deliberately separates shutdown and lifetime release. Call trevrpc_channel_close(channel) first, then trevrpc_channel_release(channel). Close is idempotent and callback-safe. Final release joins workers and frees the handle; no new channel API call may begin concurrently with release.

Testing Guidance

Test connection loss independently from RPC status failures:

  1. Start every RPC shape on one generation.
  2. Terminate the connection after the server receives at least one request.
  3. Verify every affected RPC fails exactly once and no request appears on the next generation.
  4. Verify new calls fail immediately during reconnection.
  5. Wait for readiness and verify a newly issued RPC succeeds on the later generation.
  6. Test path migration without expecting a generation change.
  7. Test resumed and full handshakes as equivalent correctness paths, with 0-RTT application data disabled where TrevRPC controls it.