diff --git a/api/v1alpha1/timeout_types.go b/api/v1alpha1/timeout_types.go index 36c0c320ed2..008582578d1 100644 --- a/api/v1alpha1/timeout_types.go +++ b/api/v1alpha1/timeout_types.go @@ -40,6 +40,11 @@ type HTTPTimeout struct { // // +optional MaxConnectionDuration *gwapiv1.Duration `json:"maxConnectionDuration,omitempty"` + + // RequestTimeout is the time until which entire response is received from the upstream. + // + // +optional + RequestTimeout *gwapiv1.Duration `json:"requestTimeout,omitempty" yaml:"requestTimeout,omitempty"` } type ClientTimeout struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index cde4e3b90d7..1fad0493923 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -2629,6 +2629,11 @@ func (in *HTTPTimeout) DeepCopyInto(out *HTTPTimeout) { *out = new(apisv1.Duration) **out = **in } + if in.RequestTimeout != nil { + in, out := &in.RequestTimeout, &out.RequestTimeout + *out = new(apisv1.Duration) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPTimeout. diff --git a/internal/gatewayapi/clustersettings.go b/internal/gatewayapi/clustersettings.go index a05ad60ff26..4df7e19174d 100644 --- a/internal/gatewayapi/clustersettings.go +++ b/internal/gatewayapi/clustersettings.go @@ -81,11 +81,11 @@ func translateTrafficFeatures(policy *egv1a1.ClusterSettings) (*ir.TrafficFeatur return ret, nil } -func buildClusterSettingsTimeout(policy egv1a1.ClusterSettings, traffic *ir.TrafficFeatures) (*ir.Timeout, error) { +func buildClusterSettingsTimeout(policy egv1a1.ClusterSettings, routeTrafficFeatures *ir.TrafficFeatures) (*ir.Timeout, error) { if policy.Timeout == nil { - if traffic != nil { + if routeTrafficFeatures != nil { // Don't lose any existing timeout definitions. - return mergeTimeoutSettings(nil, traffic.Timeout), nil + return mergeTimeoutSettings(nil, routeTrafficFeatures.Timeout), nil } return nil, nil } @@ -109,6 +109,7 @@ func buildClusterSettingsTimeout(policy egv1a1.ClusterSettings, traffic *ir.Traf if pto.HTTP != nil { var cit *metav1.Duration var mcd *metav1.Duration + var rt *metav1.Duration if pto.HTTP.ConnectionIdleTimeout != nil { d, err := time.ParseDuration(string(*pto.HTTP.ConnectionIdleTimeout)) @@ -128,19 +129,27 @@ func buildClusterSettingsTimeout(policy egv1a1.ClusterSettings, traffic *ir.Traf } } + if pto.HTTP.RequestTimeout != nil { + d, err := time.ParseDuration(string(*pto.HTTP.RequestTimeout)) + if err != nil { + errs = errors.Join(errs, fmt.Errorf("invalid RequestTimeout value %s", *pto.HTTP.RequestTimeout)) + } else { + rt = ptr.To(metav1.Duration{Duration: d}) + } + } + to.HTTP = &ir.HTTPTimeout{ ConnectionIdleTimeout: cit, MaxConnectionDuration: mcd, + RequestTimeout: rt, } } - // http request timeout is translated during the gateway-api route resource translation - // merge route timeout setting with backendtrafficpolicy timeout settings. - // Merging is done after the clustersettings definitions are translated so that - // clustersettings will override previous settings. - if traffic != nil { - to = mergeTimeoutSettings(to, traffic.Timeout) + // The timeout from route's TrafficFeatures takes precedence over the timeout in BTP + if routeTrafficFeatures != nil { + to = mergeTimeoutSettings(routeTrafficFeatures.Timeout, to) } + return to, errs } diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.in.yaml index ef8843f70c4..30a9a3133ab 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.in.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.in.yaml @@ -62,6 +62,8 @@ httpRoutes: backendRefs: - name: service-1 port: 8080 + timeouts: + request: 1s backendTrafficPolicies: - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy @@ -79,6 +81,7 @@ backendTrafficPolicies: http: connectionIdleTimeout: 16s maxConnectionDuration: 17s + requestTimeout: 18s - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy metadata: @@ -95,3 +98,4 @@ backendTrafficPolicies: http: connectionIdleTimeout: 21s maxConnectionDuration: 22s + requestTimeout: 23s diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml index 5213fc9d6a2..67cd04db0cd 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml @@ -14,6 +14,7 @@ backendTrafficPolicies: http: connectionIdleTimeout: 21s maxConnectionDuration: 22s + requestTimeout: 23s tcp: connectTimeout: 20s status: @@ -46,6 +47,7 @@ backendTrafficPolicies: http: connectionIdleTimeout: 16s maxConnectionDuration: 17s + requestTimeout: 18s tcp: connectTimeout: 15s status: @@ -195,6 +197,8 @@ httpRoutes: - backendRefs: - name: service-1 port: 8080 + timeouts: + request: 1s matches: - path: value: / @@ -289,6 +293,7 @@ xdsIR: http: connectionIdleTimeout: 16s maxConnectionDuration: 17s + requestTimeout: 18s tcp: connectTimeout: 15s envoy-gateway/gateway-2: @@ -336,5 +341,6 @@ xdsIR: http: connectionIdleTimeout: 21s maxConnectionDuration: 22s + requestTimeout: 1s # Overwritten by the request timeout in HTTPRoute tcp: connectTimeout: 20s diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 802efac5828..777884fe1cf 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -1911,6 +1911,7 @@ _Appears in:_ | --- | --- | --- | --- | | `connectionIdleTimeout` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | The idle timeout for an HTTP connection. Idle time is defined as a period in which there are no active requests in the connection.
Default: 1 hour. | | `maxConnectionDuration` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | The maximum duration of an HTTP connection.
Default: unlimited. | +| `requestTimeout` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | RequestTimeout is the time until which entire response is received from the upstream. | #### HTTPWasmCodeSource diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md index 802efac5828..777884fe1cf 100644 --- a/site/content/zh/latest/api/extension_types.md +++ b/site/content/zh/latest/api/extension_types.md @@ -1911,6 +1911,7 @@ _Appears in:_ | --- | --- | --- | --- | | `connectionIdleTimeout` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | The idle timeout for an HTTP connection. Idle time is defined as a period in which there are no active requests in the connection.
Default: 1 hour. | | `maxConnectionDuration` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | The maximum duration of an HTTP connection.
Default: unlimited. | +| `requestTimeout` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | RequestTimeout is the time until which entire response is received from the upstream. | #### HTTPWasmCodeSource