Skip to content

Add with_max_connection_idle (idle connection reaping) #177

Description

@iainmcgin

Summary

Add with_max_connection_idle to Server / BoundServer: gracefully close a connection (GOAWAY, then the existing grace period) once it has had no in-flight requests for a configured duration.

impl Server {  // and BoundServer
    /// Retire a connection that has been idle (no in-flight requests) for
    /// `duration`, by sending GOAWAY and then draining over the
    /// max-connection-age grace period. Disabled by default.
    pub fn with_max_connection_idle(self, duration: Duration) -> Self { ... }
}

Motivation

This complements the time-based with_max_connection_age (#165): age caps total lifetime regardless of use, idle reclaims connections that have gone quiet (clients behind NAT, bursty workloads, pooled clients holding connections they no longer need). It's part of the standard server connection-management set:

  • grpc-go keepalive.ServerParameters.MaxConnectionIdle (default infinity / disabled)
  • grpc-java maxConnectionIdle (default disabled)
  • x/net/http2 http2.Server.IdleTimeout (used by connect-go)
  • Traefik respondingTimeouts.idleTimeout (default 180s)

No axum::serve escape hatch exists for it.

Implementation

Unlike keepalive/max-concurrent-streams, hyper does not offer a built-in idle-then-GOAWAY for h2, so this needs logic in the per-connection ConnectionLifecycle state machine added in #165:

  • Track last-activity (reset an idle timer whenever a request starts / the connection has >0 active streams; arm it when streams drop to zero).
  • When the idle timer fires, take the same graceful_shutdown() + grace path the age timer takes.
  • Interacts with max_connection_age (whichever fires first retires the connection) and whole-server graceful shutdown (still drains indefinitely).

Detecting "active stream count" may need a hook at the tower service_fn dispatch boundary (increment on call, decrement on completion) since hyper doesn't surface per-connection stream counts directly.

Acceptance

  • with_max_connection_idle(d) on both types, disabled by default.
  • Idle connection receives GOAWAY after d of no in-flight requests, then force-closes after the grace period.
  • A connection with steady traffic is never retired by the idle timer.
  • Correct interaction with max_connection_age and graceful shutdown; tests for each.

Context: server-config audit comparing connectrpc-rs against tonic/grpc-go/grpc-java/connect-go/connect-es.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions