Skip to content

Commit 96fd1dd

Browse files
authored
feat Route Timeouts (#1899)
* feat Route Timeouts Fixes: #877 Signed-off-by: Arko Dasgupta <[email protected]> * only implement timeout, not retry Signed-off-by: Arko Dasgupta <[email protected]> * lint Signed-off-by: Arko Dasgupta <[email protected]> --------- Signed-off-by: Arko Dasgupta <[email protected]>
1 parent a785be8 commit 96fd1dd

14 files changed

+447
-0
lines changed

internal/gatewayapi/route.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package gatewayapi
88
import (
99
"fmt"
1010
"strings"
11+
"time"
1112

1213
corev1 "k8s.io/api/core/v1"
1314
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -187,6 +188,24 @@ func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRe
187188
return routeRoutes
188189
}
189190

191+
func processTimeout(irRoute *ir.HTTPRoute, rule v1beta1.HTTPRouteRule) {
192+
if rule.Timeouts != nil {
193+
if rule.Timeouts.Request != nil {
194+
// TODO: handle parse errors
195+
d, _ := time.ParseDuration(string(*rule.Timeouts.Request))
196+
irRoute.Timeout = ptr.To(metav1.Duration{Duration: d})
197+
}
198+
199+
// Also set the IR Route Timeout to the backend request timeout
200+
// until we introduce retries, then set it to per try timeout
201+
if rule.Timeouts.BackendRequest != nil {
202+
// TODO: handle parse errors
203+
d, _ := time.ParseDuration(string(*rule.Timeouts.BackendRequest))
204+
irRoute.Timeout = ptr.To(metav1.Duration{Duration: d})
205+
}
206+
}
207+
}
208+
190209
func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx int, httpFiltersContext *HTTPFiltersContext, rule v1beta1.HTTPRouteRule) []*ir.HTTPRoute {
191210
var ruleRoutes []*ir.HTTPRoute
192211

@@ -195,6 +214,7 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i
195214
irRoute := &ir.HTTPRoute{
196215
Name: irRouteName(httpRoute, ruleIdx, -1),
197216
}
217+
processTimeout(irRoute, rule)
198218
applyHTTPFiltersContextToIRRoute(httpFiltersContext, irRoute)
199219
ruleRoutes = append(ruleRoutes, irRoute)
200220
}
@@ -206,6 +226,7 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i
206226
irRoute := &ir.HTTPRoute{
207227
Name: irRouteName(httpRoute, ruleIdx, matchIdx),
208228
}
229+
processTimeout(irRoute, rule)
209230

210231
if match.Path != nil {
211232
switch PathMatchTypeDerefOr(match.Path.Type, v1beta1.PathMatchPathPrefix) {
@@ -297,6 +318,7 @@ func applyHTTPFiltersContextToIRRoute(httpFiltersContext *HTTPFiltersContext, ir
297318
if httpFiltersContext.RateLimit != nil {
298319
irRoute.RateLimit = httpFiltersContext.RateLimit
299320
}
321+
300322
if len(httpFiltersContext.ExtensionRefs) > 0 {
301323
irRoute.ExtensionRefs = httpFiltersContext.ExtensionRefs
302324
}
@@ -538,6 +560,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route
538560
Mirrors: routeRoute.Mirrors,
539561
RequestAuthentication: routeRoute.RequestAuthentication,
540562
RateLimit: routeRoute.RateLimit,
563+
Timeout: routeRoute.Timeout,
541564
ExtensionRefs: routeRoute.ExtensionRefs,
542565
}
543566
// Don't bother copying over the weights unless the route has invalid backends.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
gateways:
2+
- apiVersion: gateway.networking.k8s.io/v1beta1
3+
kind: Gateway
4+
metadata:
5+
namespace: envoy-gateway
6+
name: gateway-1
7+
spec:
8+
gatewayClassName: envoy-gateway-class
9+
listeners:
10+
- name: http
11+
protocol: HTTP
12+
port: 80
13+
allowedRoutes:
14+
namespaces:
15+
from: All
16+
httpRoutes:
17+
- apiVersion: gateway.networking.k8s.io/v1beta1
18+
kind: HTTPRoute
19+
metadata:
20+
namespace: default
21+
name: httproute-1
22+
spec:
23+
parentRefs:
24+
- namespace: envoy-gateway
25+
name: gateway-1
26+
sectionName: http
27+
rules:
28+
- matches:
29+
- path:
30+
value: "/"
31+
timeouts:
32+
backendRequest: 1s
33+
backendRefs:
34+
- name: service-1
35+
port: 8080
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
gateways:
2+
- apiVersion: gateway.networking.k8s.io/v1beta1
3+
kind: Gateway
4+
metadata:
5+
creationTimestamp: null
6+
name: gateway-1
7+
namespace: envoy-gateway
8+
spec:
9+
gatewayClassName: envoy-gateway-class
10+
listeners:
11+
- allowedRoutes:
12+
namespaces:
13+
from: All
14+
name: http
15+
port: 80
16+
protocol: HTTP
17+
status:
18+
listeners:
19+
- attachedRoutes: 1
20+
conditions:
21+
- lastTransitionTime: null
22+
message: Sending translated listener configuration to the data plane
23+
reason: Programmed
24+
status: "True"
25+
type: Programmed
26+
- lastTransitionTime: null
27+
message: Listener has been successfully translated
28+
reason: Accepted
29+
status: "True"
30+
type: Accepted
31+
name: http
32+
supportedKinds:
33+
- group: gateway.networking.k8s.io
34+
kind: HTTPRoute
35+
- group: gateway.networking.k8s.io
36+
kind: GRPCRoute
37+
httpRoutes:
38+
- apiVersion: gateway.networking.k8s.io/v1beta1
39+
kind: HTTPRoute
40+
metadata:
41+
creationTimestamp: null
42+
name: httproute-1
43+
namespace: default
44+
spec:
45+
parentRefs:
46+
- name: gateway-1
47+
namespace: envoy-gateway
48+
sectionName: http
49+
rules:
50+
- backendRefs:
51+
- name: service-1
52+
port: 8080
53+
matches:
54+
- path:
55+
value: /
56+
timeouts:
57+
backendRequest: 1s
58+
status:
59+
parents:
60+
- conditions:
61+
- lastTransitionTime: null
62+
message: Route is accepted
63+
reason: Accepted
64+
status: "True"
65+
type: Accepted
66+
- lastTransitionTime: null
67+
message: Resolved all the Object references for the Route
68+
reason: ResolvedRefs
69+
status: "True"
70+
type: ResolvedRefs
71+
controllerName: gateway.envoyproxy.io/gatewayclass-controller
72+
parentRef:
73+
name: gateway-1
74+
namespace: envoy-gateway
75+
sectionName: http
76+
infraIR:
77+
envoy-gateway/gateway-1:
78+
proxy:
79+
listeners:
80+
- address: ""
81+
ports:
82+
- containerPort: 10080
83+
name: http
84+
protocol: HTTP
85+
servicePort: 80
86+
metadata:
87+
labels:
88+
gateway.envoyproxy.io/owning-gateway-name: gateway-1
89+
gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
90+
name: envoy-gateway/gateway-1
91+
xdsIR:
92+
envoy-gateway/gateway-1:
93+
accessLog:
94+
text:
95+
- path: /dev/stdout
96+
http:
97+
- address: 0.0.0.0
98+
hostnames:
99+
- '*'
100+
isHTTP2: false
101+
name: envoy-gateway/gateway-1/http
102+
port: 10080
103+
routes:
104+
- backendWeights:
105+
invalid: 0
106+
valid: 0
107+
destination:
108+
name: httproute/default/httproute-1/rule/0
109+
settings:
110+
- endpoints:
111+
- host: 7.7.7.7
112+
port: 8080
113+
weight: 1
114+
hostname: '*'
115+
name: httproute/default/httproute-1/rule/0/match/0/*
116+
pathMatch:
117+
distinct: false
118+
name: ""
119+
prefix: /
120+
timeout: 1s
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
gateways:
2+
- apiVersion: gateway.networking.k8s.io/v1beta1
3+
kind: Gateway
4+
metadata:
5+
namespace: envoy-gateway
6+
name: gateway-1
7+
spec:
8+
gatewayClassName: envoy-gateway-class
9+
listeners:
10+
- name: http
11+
protocol: HTTP
12+
port: 80
13+
allowedRoutes:
14+
namespaces:
15+
from: All
16+
httpRoutes:
17+
- apiVersion: gateway.networking.k8s.io/v1beta1
18+
kind: HTTPRoute
19+
metadata:
20+
namespace: default
21+
name: httproute-1
22+
spec:
23+
parentRefs:
24+
- namespace: envoy-gateway
25+
name: gateway-1
26+
sectionName: http
27+
rules:
28+
- matches:
29+
- path:
30+
value: "/"
31+
timeouts:
32+
request: 5s
33+
backendRefs:
34+
- name: service-1
35+
port: 8080
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
gateways:
2+
- apiVersion: gateway.networking.k8s.io/v1beta1
3+
kind: Gateway
4+
metadata:
5+
creationTimestamp: null
6+
name: gateway-1
7+
namespace: envoy-gateway
8+
spec:
9+
gatewayClassName: envoy-gateway-class
10+
listeners:
11+
- allowedRoutes:
12+
namespaces:
13+
from: All
14+
name: http
15+
port: 80
16+
protocol: HTTP
17+
status:
18+
listeners:
19+
- attachedRoutes: 1
20+
conditions:
21+
- lastTransitionTime: null
22+
message: Sending translated listener configuration to the data plane
23+
reason: Programmed
24+
status: "True"
25+
type: Programmed
26+
- lastTransitionTime: null
27+
message: Listener has been successfully translated
28+
reason: Accepted
29+
status: "True"
30+
type: Accepted
31+
name: http
32+
supportedKinds:
33+
- group: gateway.networking.k8s.io
34+
kind: HTTPRoute
35+
- group: gateway.networking.k8s.io
36+
kind: GRPCRoute
37+
httpRoutes:
38+
- apiVersion: gateway.networking.k8s.io/v1beta1
39+
kind: HTTPRoute
40+
metadata:
41+
creationTimestamp: null
42+
name: httproute-1
43+
namespace: default
44+
spec:
45+
parentRefs:
46+
- name: gateway-1
47+
namespace: envoy-gateway
48+
sectionName: http
49+
rules:
50+
- backendRefs:
51+
- name: service-1
52+
port: 8080
53+
matches:
54+
- path:
55+
value: /
56+
timeouts:
57+
request: 5s
58+
status:
59+
parents:
60+
- conditions:
61+
- lastTransitionTime: null
62+
message: Route is accepted
63+
reason: Accepted
64+
status: "True"
65+
type: Accepted
66+
- lastTransitionTime: null
67+
message: Resolved all the Object references for the Route
68+
reason: ResolvedRefs
69+
status: "True"
70+
type: ResolvedRefs
71+
controllerName: gateway.envoyproxy.io/gatewayclass-controller
72+
parentRef:
73+
name: gateway-1
74+
namespace: envoy-gateway
75+
sectionName: http
76+
infraIR:
77+
envoy-gateway/gateway-1:
78+
proxy:
79+
listeners:
80+
- address: ""
81+
ports:
82+
- containerPort: 10080
83+
name: http
84+
protocol: HTTP
85+
servicePort: 80
86+
metadata:
87+
labels:
88+
gateway.envoyproxy.io/owning-gateway-name: gateway-1
89+
gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
90+
name: envoy-gateway/gateway-1
91+
xdsIR:
92+
envoy-gateway/gateway-1:
93+
accessLog:
94+
text:
95+
- path: /dev/stdout
96+
http:
97+
- address: 0.0.0.0
98+
hostnames:
99+
- '*'
100+
isHTTP2: false
101+
name: envoy-gateway/gateway-1/http
102+
port: 10080
103+
routes:
104+
- backendWeights:
105+
invalid: 0
106+
valid: 0
107+
destination:
108+
name: httproute/default/httproute-1/rule/0
109+
settings:
110+
- endpoints:
111+
- host: 7.7.7.7
112+
port: 8080
113+
weight: 1
114+
hostname: '*'
115+
name: httproute/default/httproute-1/rule/0/match/0/*
116+
pathMatch:
117+
distinct: false
118+
name: ""
119+
prefix: /
120+
timeout: 5s

internal/ir/xds.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"golang.org/x/exp/slices"
1515

1616
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
17+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1718
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1819

1920
egcfgv1a1 "github.com/envoyproxy/gateway/api/config/v1alpha1"
@@ -273,6 +274,8 @@ type HTTPRoute struct {
273274
RateLimit *RateLimit `json:"rateLimit,omitempty" yaml:"rateLimit,omitempty"`
274275
// RequestAuthentication defines the schema for authenticating HTTP requests.
275276
RequestAuthentication *RequestAuthentication `json:"requestAuthentication,omitempty" yaml:"requestAuthentication,omitempty"`
277+
// Timeout is the time until which entire response is received from the upstream.
278+
Timeout *metav1.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"`
276279
// ExtensionRefs holds unstructured resources that were introduced by an extension and used on the HTTPRoute as extensionRef filters
277280
ExtensionRefs []*UnstructuredRef `json:"extensionRefs,omitempty" yaml:"extensionRefs,omitempty"`
278281
}

0 commit comments

Comments
 (0)