Move the `BuildHasher`/`Hasher` import out of `random_duration` and into
the module-level `use` block.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Add the CHANGELOG entry for `ConnectionLimits` (#3779), and gate the
`TokioTimer` import under `feature = "http1"` since it is only used there,
fixing a pre-existing unused-import warning in http2-only builds.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Add `axum::serve::ConnectionLimits`, applied via `Serve::connection_limits`
(and the `WithGracefulShutdown` equivalent), to bound the lifetime of
individual connections and force clients to rotate connections.
This is useful behind a load balancer that round-robins new connections
across backends: without rotation a client's connection pool keeps sending
work to the backends it first connected to, even after the pool has scaled
up. It mirrors tonic's `max_connection_age` and Envoy's
`max_connection_duration`.
Three knobs are supported:
- `max_connection_age`: soft cap on total connection lifetime. When it
elapses the connection is gracefully shut down (HTTP/1 `Connection: close`
after the in-flight request, HTTP/2 `GOAWAY`).
- `max_connection_age_jitter`: random per-connection jitter added to the age
limit, to avoid synchronized reconnect storms.
- `max_connection_age_grace`: hard cap on how long to wait for in-flight work
after the age limit fires before forcibly closing.
The mechanism reuses hyper's per-connection `graceful_shutdown`, the same
primitive `with_graceful_shutdown` already uses. Jitter uses `RandomState`
for cheap randomness without a new dependency.
Closes#3753
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
## Motivation
axum::serve hardcodes TokioExecutor for spawning connection tasks and hyper's internal HTTP/2 tasks. This is the one thing that cannot be customized by wrapping axum's API from the outside, users are forced to reimplement the entire serve loop (~150 lines) just to swap the executor.
This is needed for use cases like runtime telemetry (e.g. dial9-tokio-telemetry) where we want to wrap task spawning, so that we can capture things like wake events.
The goal of this feature is to allow hooking into the current tokio spawns (by being able to set an executor that provides them, rather than hardcoding them) to attach instrumentation. The goal is not the make serve fully runtime agnostic.
## Solution
This PR adds Serve::with_executor() and WithGracefulShutdown::with_executor() builder methods that take an Executor, and an axum::serve::Executor trait for defining the Executor interface.
The default remains a new TokioExecutor (that spawns tokio spawns just like before), so we maintain backward compatibility.
Small design note: this defines a new axum::serve::Executor trait rather than reuse of hyper::rt::Executor<Fut> directly, because the latter is generic at the trait level and I couldn't find a way to bound E to cover all the internal future types hyper needs. So this new trait uses a generic method instead, and then a HyperExecutor<E> adapter bridges to hyper.
The new version now supports prefix and suffix captures such as `/{file}.png`, `/avatar.{extension}`, and `/user-{id}.png`.
Co-authored-by: David Mládek <[email protected]>