From b48b662050da7f9d87ac51f9a2f2307a15ed57a1 Mon Sep 17 00:00:00 2001 From: Andrey Maltsev Date: Fri, 31 Jul 2026 15:39:26 +0300 Subject: [PATCH 1/3] docs: add GRPC Timeouts task (BackendTrafficPolicy) GRPCRoute has no native timeouts field yet (tracked upstream at kubernetes-sigs/gateway-api#3139), and users repeatedly rediscover the BackendTrafficPolicy workaround by word of mouth. Document how to configure gRPC timeouts via BackendTrafficPolicy: requestTimeout for unary RPCs, and requestTimeout: 0s + maxStreamDuration/streamIdleTimeout for streaming RPCs. Signed-off-by: Andrey Maltsev --- .../en/latest/tasks/traffic/grpc-timeouts.md | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 site/content/en/latest/tasks/traffic/grpc-timeouts.md diff --git a/site/content/en/latest/tasks/traffic/grpc-timeouts.md b/site/content/en/latest/tasks/traffic/grpc-timeouts.md new file mode 100644 index 0000000000..78927daf01 --- /dev/null +++ b/site/content/en/latest/tasks/traffic/grpc-timeouts.md @@ -0,0 +1,151 @@ +--- +title: "GRPC Timeouts" +--- + +Unlike [HTTPRoute][], the Gateway API [GRPCRoute][] resource does not (yet) expose a native +`timeouts` field — see the upstream tracking issue [Support Request Timeouts for GRPCRoute][gapi-3139]. +Until that lands, Envoy Gateway lets you configure timeouts for gRPC traffic with a +[BackendTrafficPolicy][] that targets the `GRPCRoute`. + +The default request timeout is 15 seconds in Envoy Proxy, which will terminate long-lived +streaming RPCs. The relevant `spec.timeout.http` fields are: + +- **requestTimeout**: the maximum duration for the entire response to be received from the + upstream. This bounds **unary** RPCs. Set it to `"0s"` to disable it for **streaming** RPCs, + which otherwise would be cut off once the timeout elapses. +- **maxStreamDuration**: the maximum duration of a stream, measured from when the request is sent + until the response stream is fully consumed. It does not apply to non-streaming requests. Set it + to `"0s"` to allow streams to run indefinitely. +- **streamIdleTimeout**: the amount of time a stream may exist with no upstream or downstream + activity. Use this to reclaim idle streams without capping a healthy long-lived stream's total + duration. + +## Prerequisites + +{{< boilerplate prerequisites >}} + +Follow the [GRPC Routing](../grpc-routing) task to set up a `Gateway` and a `GRPCRoute` named +`yages` before configuring timeouts. + +## Unary RPCs + +Set `requestTimeout` to bound the duration of unary RPCs. Here, unary calls that take longer than +5 seconds are terminated with a timeout. + +{{< tabpane text=true >}} +{{% tab header="Apply from stdin" %}} + +```shell +cat <}} + +## Streaming RPCs + +For server-streaming, client-streaming, or bidirectional-streaming RPCs, `requestTimeout` would +terminate the stream once it elapses. Disable it with `"0s"` and, if you want an upper bound, use +`maxStreamDuration` (or `streamIdleTimeout` to reclaim only idle streams). The example below lets +streams run indefinitely while reclaiming streams that are idle for more than 1 hour. + +{{< tabpane text=true >}} +{{% tab header="Apply from stdin" %}} + +```shell +cat <}} + +## Verification + +Confirm the policy is accepted: + +```shell +kubectl get backendtrafficpolicy/grpc-stream-timeout -o yaml +``` + +The status should reflect `Accepted=True` on the targeted `GRPCRoute` ancestor. + +[HTTPRoute]: https://gateway-api.sigs.k8s.io/api-types/httproute/ +[GRPCRoute]: https://gateway-api.sigs.k8s.io/api-types/grpcroute/ +[BackendTrafficPolicy]: ../../../api/extension_types#backendtrafficpolicy +[gapi-3139]: https://github.com/kubernetes-sigs/gateway-api/issues/3139 From 2c855639876923b4e8208d86617af104fe7c8ba6 Mon Sep 17 00:00:00 2001 From: Andrey Maltsev Date: Fri, 31 Jul 2026 15:45:48 +0300 Subject: [PATCH 2/3] =?UTF-8?q?docs:=20address=20review=20=E2=80=94=20use?= =?UTF-8?q?=20a=20single=20BackendTrafficPolicy=20for=20the=20grpc-timeout?= =?UTF-8?q?s=20examples?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A GRPCRoute accepts only one BackendTrafficPolicy; a second policy targeting the same route is rejected as Conflicted (backendtrafficpolicy.go resolveBackendTrafficPolicyRouteTargetRef). The unary and streaming examples now reuse a single policy name (grpc-timeouts) and a note explains they are alternatives, so following the task top-to-bottom no longer produces a Conflicted second policy. Signed-off-by: Andrey Maltsev --- .../en/latest/tasks/traffic/grpc-timeouts.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/site/content/en/latest/tasks/traffic/grpc-timeouts.md b/site/content/en/latest/tasks/traffic/grpc-timeouts.md index 78927daf01..6ba311abdf 100644 --- a/site/content/en/latest/tasks/traffic/grpc-timeouts.md +++ b/site/content/en/latest/tasks/traffic/grpc-timeouts.md @@ -27,6 +27,12 @@ streaming RPCs. The relevant `spec.timeout.http` fields are: Follow the [GRPC Routing](../grpc-routing) task to set up a `Gateway` and a `GRPCRoute` named `yages` before configuring timeouts. +__Note:__ A `GRPCRoute` can have at most one `BackendTrafficPolicy` attached to it; a second policy +targeting the same route is rejected as `Conflicted`. The two examples below are therefore +alternatives that reuse the same policy name (`grpc-timeouts`) — pick the one that matches your +workload. Re-applying with the same `metadata.name` updates the existing policy rather than creating +a conflicting second one. + ## Unary RPCs Set `requestTimeout` to bound the duration of unary RPCs. Here, unary calls that take longer than @@ -40,7 +46,7 @@ cat < Date: Fri, 31 Jul 2026 20:18:11 +0300 Subject: [PATCH 3/3] docs: fix gateway-api reference links and add timeout verification - Correct the HTTPRoute/GRPCRoute links to the /reference/api-types/ path used by the other traffic docs (the /api-types/ form 404s, failing docs-lint link check). - Address review: add a Verification step that proves the timeout is programmed into the Envoy route config via egctl (route timeout / maxStreamDuration), plus an end-to-end grpcurl DEADLINE_EXCEEDED example and a note that the sample yages backend does not delay. Signed-off-by: Andrey Maltsev --- .../en/latest/tasks/traffic/grpc-timeouts.md | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/site/content/en/latest/tasks/traffic/grpc-timeouts.md b/site/content/en/latest/tasks/traffic/grpc-timeouts.md index 6ba311abdf..6d6d4829c5 100644 --- a/site/content/en/latest/tasks/traffic/grpc-timeouts.md +++ b/site/content/en/latest/tasks/traffic/grpc-timeouts.md @@ -143,7 +143,7 @@ spec: ## Verification -Confirm the policy is accepted: +First confirm the policy is accepted: ```shell kubectl get backendtrafficpolicy/grpc-timeouts -o yaml @@ -151,7 +151,32 @@ kubectl get backendtrafficpolicy/grpc-timeouts -o yaml The status should reflect `Accepted=True` on the targeted `GRPCRoute` ancestor. -[HTTPRoute]: https://gateway-api.sigs.k8s.io/api-types/httproute/ -[GRPCRoute]: https://gateway-api.sigs.k8s.io/api-types/grpcroute/ +Then confirm the timeout is actually programmed into the Envoy route config with +[egctl](../../operations/egctl): + +```shell +egctl config envoy-proxy route \ + --labels gateway.envoyproxy.io/owning-gateway-name=eg,gateway.envoyproxy.io/owning-gateway-namespace=default \ + -o yaml | grep -A2 -E 'timeout|maxStreamDuration' +``` + +For the **unary** example you should see the route's `timeout` set to the configured +`requestTimeout` (e.g. `timeout: 5s`). For the **streaming** example you should see +`timeout: 0s` (disabled) together with `maxStreamDuration` on the route action. + +To exercise the timeout end-to-end you need a gRPC backend that can delay or stream (the +sample `yages` echo server used in the [GRPC Routing](../grpc-routing) task returns +immediately). Against such a backend, a unary call that exceeds `requestTimeout` returns +gRPC status `DEADLINE_EXCEEDED` (HTTP `504`), for example with +[grpcurl](https://github.com/fullstorydev/grpcurl): + +```shell +grpcurl -plaintext -authority=grpc-example.com ${GATEWAY_HOST}:80 +# ERROR: +# Code: DeadlineExceeded +``` + +[HTTPRoute]: https://gateway-api.sigs.k8s.io/reference/api-types/httproute/ +[GRPCRoute]: https://gateway-api.sigs.k8s.io/reference/api-types/grpcroute/ [BackendTrafficPolicy]: ../../../api/extension_types#backendtrafficpolicy [gapi-3139]: https://github.com/kubernetes-sigs/gateway-api/issues/3139