kubernetes-sigs / kubernetes-sigs/gateway-api

Standard connection draining semantics for long-lived HTTP connections

Open
#5,014 3 comments 0 reactions 0 assignees View on GitHub
kind/feature
Dominant language
Go
Stars
3k
Forks
789
Avg merge
2d 15h
Merged PRs (30d)
45

Description

**What would you like to be added**:

I would like Gateway API to define standard connection draining semantics for long-lived HTTP connections, especially WebSocket, Server-Sent Events (SSE), and long-lived gRPC/HTTP streams.

Gateway API already supports identifying WebSocket backends through `Service.spec.ports[].appProtocol` values such as `kubernetes.io/ws` and `kubernetes.io/wss`, and Kubernetes EndpointSlice already exposes `serving`, `terminating`, and `ready` endpoint conditions.

However, there does not appear to be a portable Gateway API-level policy or guidance that describes how implementations should drain long-lived connections during backend Pod termination, Gateway data plane termination, rolling updates, scale-down, or node drain.

This issue is intended to explore whether Gateway API should standardize a small set of connection draining semantics, for example:

* Stop routing new long-lived HTTP connections to backends whose EndpointSlice condition is `terminating: true`.
* Continue serving existing long-lived connections to a terminating backend while `serving: true`, until a configurable drain timeout expires.
* Provide an implementation-independent way to configure a drain timeout for Gateway-managed data planes and/or backend connections.
* Define expected behavior for WebSocket, SSE, and streaming HTTP/gRPC connections during rolling updates and scale-down.
* Clarify whether this belongs in existing route timeout policy, BackendTLSPolicy-style policy attachment, a new policy type, implementation guidance, or conformance documentation.

A possible API direction could be something like a policy that attaches to `Gateway`, `HTTPRoute`, or `Service` backends:

```yaml
apiVersion: gateway.networking.k8s.io/v1alphaX
kind: ConnectionDrainPolicy
metadata:
name: long-lived-http-drain
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: realtime-route
drainTimeout: 10m
applyTo:
- WebSocket
- ServerSentEvents
- StreamingHTTP
- StreamingGRPC
```

This is only an example shape. The main request is not a specific API yet, but a standard set of semantics that Gateway API implementations can converge on.

Related discussion:

* kubernetes/kubernetes#140018

**Why this is needed**:

Long-lived HTTP connections behave differently from ordinary request/response HTTP traffic. A WebSocket or streaming request can remain open for minutes or hours. During rolling updates or scale-down, users often want the following behavior:

* Existing WebSocket or streaming clients remain connected to the old backend while it drains.
* New connections are routed to non-terminating backends.
* The old backend exits after all connections finish, or after a configured drain timeout.
* The behavior is portable across Gateway API implementations.

Today, this behavior is implementation-specific. Some implementations, such as Envoy Gateway, provide graceful shutdown and configurable drain timeouts for their own data plane. Other ingress controllers or service mesh implementations have their own approaches.

Kubernetes itself exposes useful primitives through EndpointSlice `serving` and `terminating` conditions, but Gateway API does not seem to define how Gateway implementations should use those signals for long-lived HTTP connections.

This creates a portability gap for realtime applications such as:

* collaborative editors
* chat and presence systems
* multiplayer or realtime session services
* AI streaming APIs
* live transcription
* notification gateways
* dashboards using WebSocket or SSE
* long-lived gRPC streams

Without common semantics, users must rely on controller-specific annotations, custom `preStop` hooks, sidecars, sticky sessions, or application-level reconnect logic. Those approaches can work, but they make behavior hard to reason about and hard to migrate across Gateway API implementations.

This proposal is intentionally scoped to graceful draining. It is not proposing transparent migration of an existing TCP/WebSocket connection from one Pod to another after the Pod has already died. That is likely outside the scope of Gateway API and Kubernetes Services.

The goal is to standardize drain behavior while the old endpoint or Gateway data plane is still alive.

I would be happy to help refine the problem statement, write documentation, prototype conformance expectations, or draft a GEP if maintainers think this belongs in Gateway API.

Contributor guide

Open the contributing guide

Research direction

Start by reading the related kubernetes/kubernetes#140018 discussion and the EndpointSlice serving, terminating, and ready conditions described here. No repository files or tests are identified; done would require maintainers to settle the portable semantics and choose whether they belong in policy, implementation guidance, or conformance documentation.

Written by the indexing model from the issue text.

Assessment

Domain
api, networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.