Skip to content

Commit

Permalink
feat: support HTTPRoute Retries GEP-1731 (#5024)
Browse files Browse the repository at this point in the history
* feat: support HTTPRoute Retries GEP-1731

Signed-off-by: zirain <zirain2009@gmail.com>
  • Loading branch information
zirain authored Jan 14, 2025
1 parent 271a697 commit 58a9b23
Show file tree
Hide file tree
Showing 12 changed files with 654 additions and 13 deletions.
54 changes: 47 additions & 7 deletions internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,11 @@ func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRe
return routeRoutes, nil
}

func processRouteTrafficFeatures(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) {
processRouteTimeout(irRoute, rule)
processRouteRetry(irRoute, rule)
}

func processRouteTimeout(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) {
if rule.Timeouts != nil {
if rule.Timeouts.Request != nil {
Expand All @@ -293,6 +298,45 @@ func processRouteTimeout(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) {
}
}

func processRouteRetry(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) {
if rule.Retry == nil {
return
}

retry := rule.Retry
res := &ir.Retry{}
if retry.Attempts != nil {
res.NumRetries = ptr.To(uint32(*retry.Attempts))
}
if retry.Backoff != nil {
backoff, err := time.ParseDuration(string(*retry.Backoff))
if err == nil {
res.PerRetry = &ir.PerRetryPolicy{
BackOff: &ir.BackOffPolicy{
BaseInterval: ptr.To(metav1.Duration{Duration: backoff}),
},
}
// xref: https://gateway-api.sigs.k8s.io/geps/gep-1742/#timeout-values
if rule.Timeouts != nil && rule.Timeouts.BackendRequest != nil {
backendRequestTimeout, err := time.ParseDuration(string(*rule.Timeouts.BackendRequest))
if err == nil {
res.PerRetry.Timeout = &metav1.Duration{Duration: backendRequestTimeout}
}
}
}
}
if len(retry.Codes) > 0 {
codes := make([]ir.HTTPStatus, 0, len(retry.Codes))
for _, code := range retry.Codes {
codes = append(codes, ir.HTTPStatus(code))
}
res.RetryOn = &ir.RetryOn{
HTTPStatusCodes: codes,
}
}
irRoute.Retry = res
}

func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx int, httpFiltersContext *HTTPFiltersContext, rule gwapiv1.HTTPRouteRule) ([]*ir.HTTPRoute, error) {
var ruleRoutes []*ir.HTTPRoute

Expand All @@ -302,7 +346,7 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i
Name: irRouteName(httpRoute, ruleIdx, -1),
}
irRoute.Metadata = buildRouteMetadata(httpRoute, rule.Name)
processRouteTimeout(irRoute, rule)
processRouteTrafficFeatures(irRoute, rule)
applyHTTPFiltersContextToIRRoute(httpFiltersContext, irRoute)
ruleRoutes = append(ruleRoutes, irRoute)
}
Expand Down Expand Up @@ -363,7 +407,7 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i
SessionPersistence: sessionPersistence,
}
irRoute.Metadata = buildRouteMetadata(httpRoute, rule.Name)
processRouteTimeout(irRoute, rule)
processRouteTrafficFeatures(irRoute, rule)

if match.Path != nil {
switch PathMatchTypeDerefOr(match.Path.Type, gwapiv1.PathMatchPathPrefix) {
Expand Down Expand Up @@ -751,11 +795,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route
IsHTTP2: routeRoute.IsHTTP2,
SessionPersistence: routeRoute.SessionPersistence,
Timeout: routeRoute.Timeout,
}
if routeRoute.Traffic != nil {
hostRoute.Traffic = &ir.TrafficFeatures{
Retry: routeRoute.Traffic.Retry,
}
Retry: routeRoute.Retry,
}
perHostRoutes = append(perHostRoutes, hostRoute)
}
Expand Down
100 changes: 100 additions & 0 deletions internal/gatewayapi/testdata/httproute-retry.in.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-2
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-1
spec:
hostnames:
- gateway.envoyproxy.io
parentRefs:
- namespace: envoy-gateway
name: gateway-2
sectionName: http
rules:
- matches:
- path:
value: "/"
retry:
codes:
- 500
attempts: 3
backoff: 200ms
timeouts:
backendRequest: 3s
backendRefs:
- name: service-1
port: 8080
backendTrafficPolicies:
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: envoy-gateway
name: policy-for-gateway
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
retry:
retryOn:
triggers:
- cancelled
perRetry:
timeout: 250ms
backoff:
baseInterval: 100ms
maxInterval: 10s
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: default
name: policy-for-route
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: httproute-1
retry:
numRetries: 5
retryOn:
httpStatusCodes:
- 429
- 503
triggers:
- connect-failure
- retriable-status-codes
perRetry:
timeout: 250ms
backoff:
baseInterval: 100ms
maxInterval: 10s
Loading

0 comments on commit 58a9b23

Please sign in to comment.