Skip to content

Commit 29a5dd8

Browse files
ericdbishopdprotasorobscott
authored
GEP 3388 Retry Budget API Implementation (#3607)
* apis: add implementation for GEP-3388 HTTPRoute Retry Budget * fmt and add descriptions for parameters * Move GEP 3388 to Experimental * make generate * Minor change * Require both parameters of RequestRate * Begin fixing Retry description. Add defaults, some validation, in CommonRetryPolicy * Taking the liberty of renaming CommonRetryPolicy to RetryConstraint * Shamelessly copying from backendlbpolicy and backendtlspolicy to conform with api structure * Fleshing out the description for RetryConstraint * refactor codegen scripts to make it easier to generate two clients * Attempting to match the experimental API structure that dprotaso made in #3588 * Delete files that were generated before moving to apisx * undo commenting * Working to fix code gen following merge * Fix api group name * capitalize RFC 2119 keyword * Addressing comments from code review * missing file * fix imports * Modify descriptions; add greater validation * Update apisx/v1alpha2/backendtrafficpolicy.go Co-authored-by: Rob Scott <rob.scott87@gmail.com> * Not complete, but adding CEL tests for backend traffic policy * fix missing retryConstraint in test struct; add tests for invalid config * move to apis/v1alpha1 * add main_test * rename file * fix missing quotes :) * fix CEL condition * move validation message to interval field directly * remove unused apisx/v1alpha2 file * remove more files from before merging experimental api versions --------- Co-authored-by: Dave Protasowski <dprotaso@gmail.com> Co-authored-by: Rob Scott <rob.scott87@gmail.com>
1 parent 8c7f335 commit 29a5dd8

26 files changed

+2933
-8
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1alpha1
18+
19+
import (
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
)
22+
23+
// +genclient
24+
// +kubebuilder:object:root=true
25+
// +kubebuilder:subresource:status
26+
// +kubebuilder:storageversion
27+
// +kubebuilder:resource:categories=gateway-api,shortName=btrafficpolicy
28+
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
29+
//
30+
// BackendTrafficPolicy is a Direct Attached Policy.
31+
// +kubebuilder:metadata:labels="gateway.networking.k8s.io/policy=Direct"
32+
33+
// BackendTrafficPolicy defines the configuration for how traffic to a
34+
// target backend should be handled.
35+
type BackendTrafficPolicy struct {
36+
// Support: Extended
37+
//
38+
// +optional
39+
40+
metav1.TypeMeta `json:",inline"`
41+
metav1.ObjectMeta `json:"metadata,omitempty"`
42+
43+
// Spec defines the desired state of BackendTrafficPolicy.
44+
Spec BackendTrafficPolicySpec `json:"spec"`
45+
46+
// Status defines the current state of BackendTrafficPolicy.
47+
Status PolicyStatus `json:"status,omitempty"`
48+
}
49+
50+
// BackendTrafficPolicyList contains a list of BackendTrafficPolicies
51+
// +kubebuilder:object:root=true
52+
type BackendTrafficPolicyList struct {
53+
metav1.TypeMeta `json:",inline"`
54+
metav1.ListMeta `json:"metadata,omitempty"`
55+
Items []BackendTrafficPolicy `json:"items"`
56+
}
57+
58+
// BackendTrafficPolicySpec define the desired state of BackendTrafficPolicy
59+
// Note: there is no Override or Default policy configuration.
60+
type BackendTrafficPolicySpec struct {
61+
// TargetRefs identifies API object(s) to apply this policy to.
62+
// Currently, Backends (A grouping of like endpoints such as Service,
63+
// ServiceImport, or any implementation-specific backendRef) are the only
64+
// valid API target references.
65+
//
66+
// Currently, a TargetRef can not be scoped to a specific port on a
67+
// Service.
68+
//
69+
// +listType=map
70+
// +listMapKey=group
71+
// +listMapKey=kind
72+
// +listMapKey=name
73+
// +kubebuilder:validation:MinItems=1
74+
// +kubebuilder:validation:MaxItems=16
75+
TargetRefs []LocalPolicyTargetReference `json:"targetRefs"`
76+
77+
// RetryConstraint defines the configuration for when to allow or prevent
78+
// further retries to a target backend, by dynamically calculating a 'retry
79+
// budget'. This budget is calculated based on the percentage of incoming
80+
// traffic composed of retries over a given time interval. Once the budget
81+
// is exceeded, additional retries will be rejected.
82+
//
83+
// For example, if the retry budget interval is 10 seconds, there have been
84+
// 1000 active requests in the past 10 seconds, and the allowed percentage
85+
// of requests that can be retried is 20% (the default), then 200 of those
86+
// requests may be composed of retries. Active requests will only be
87+
// considered for the duration of the interval when calculating the retry
88+
// budget. Retrying the same original request multiple times within the
89+
// retry budget interval will lead to each retry being counted towards
90+
// calculating the budget.
91+
//
92+
// Configuring a RetryConstraint in BackendTrafficPolicy is compatible with
93+
// HTTPRoute Retry settings for each HTTPRouteRule that targets the same
94+
// backend. While the HTTPRouteRule Retry stanza can specify whether a
95+
// request will be retried, and the number of retry attempts each client
96+
// may perform, RetryConstraint helps prevent cascading failures such as
97+
// retry storms during periods of consistent failures.
98+
//
99+
// After the retry budget has been exceeded, additional retries to the
100+
// backend MUST return a 503 response to the client.
101+
//
102+
// Additional configurations for defining a constraint on retries MAY be
103+
// defined in the future.
104+
//
105+
// Support: Extended
106+
//
107+
// +optional
108+
// <gateway:experimental>
109+
RetryConstraint *RetryConstraint `json:"retryConstraint,omitempty"`
110+
111+
// SessionPersistence defines and configures session persistence
112+
// for the backend.
113+
//
114+
// Support: Extended
115+
//
116+
// +optional
117+
SessionPersistence *SessionPersistence `json:"sessionPersistence,omitempty"`
118+
}
119+
120+
// RetryConstraint defines the configuration for when to retry a request.
121+
type RetryConstraint struct {
122+
// BudgetPercent defines the maximum percentage of active requests that may
123+
// be made up of retries.
124+
//
125+
// Support: Extended
126+
//
127+
// +optional
128+
// +kubebuilder:default=20
129+
// +kubebuilder:validation:Minimum=0
130+
// +kubebuilder:validation:Maximum=100
131+
BudgetPercent *int `json:"budgetPercent,omitempty"`
132+
133+
// BudgetInterval defines the duration in which requests will be considered
134+
// for calculating the budget for retries.
135+
//
136+
// Support: Extended
137+
//
138+
// +optional
139+
// +kubebuilder:default="10s"
140+
// +kubebuilder:validation:XValidation:message="budgetInterval can not be greater than one hour or less than one second",rule="!(duration(self) < duration('1s') || duration(self) > duration('1h'))"
141+
BudgetInterval *Duration `json:"budgetInterval,omitempty"`
142+
143+
// MinRetryRate defines the minimum rate of retries that will be allowable
144+
// over a specified duration of time.
145+
//
146+
// The effective overall minimum rate of retries targeting the backend
147+
// service may be much higher, as there can be any number of clients which
148+
// are applying this setting locally.
149+
//
150+
// This ensures that requests can still be retried during periods of low
151+
// traffic, where the budget for retries may be calculated as a very low
152+
// value.
153+
//
154+
// Support: Extended
155+
//
156+
// +optional
157+
// +kubebuilder:default={count: 10, interval: "1s"}
158+
MinRetryRate *RequestRate `json:"minRetryRate,omitempty"`
159+
}

apisx/v1alpha1/shared_types.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ limitations under the License.
1616

1717
package v1alpha1
1818

19-
import v1 "sigs.k8s.io/gateway-api/apis/v1"
19+
import (
20+
v1 "sigs.k8s.io/gateway-api/apis/v1"
21+
v1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
22+
)
2023

2124
type (
2225
// +k8s:deepcopy-gen=false
@@ -41,6 +44,14 @@ type (
4144
SectionName = v1.SectionName
4245
// +k8s:deepcopy-gen=false
4346
Namespace = v1.Namespace
47+
// +k8s:deepcopy-gen=false
48+
Duration = v1.Duration
49+
// +k8s:deepcopy-gen=false
50+
PolicyStatus = v1alpha2.PolicyStatus
51+
// +k8s:deepcopy-gen=false
52+
LocalPolicyTargetReference = v1alpha2.LocalPolicyTargetReference
53+
// +k8s:deepcopy-gen=false
54+
SessionPersistence = v1.SessionPersistence
4455
)
4556

4657
// ParentGatewayReference identifies an API object including its namespace,
@@ -68,3 +79,20 @@ type ParentGatewayReference struct {
6879
// +optional
6980
Namespace *Namespace `json:"namespace,omitempty"`
7081
}
82+
83+
// RequestRate expresses a rate of requests over a given period of time.
84+
type RequestRate struct {
85+
// Count specifies the number of requests per time interval.
86+
//
87+
// Support: Extended
88+
// +kubebuilder:validation:Minimum=1
89+
// +kubebuilder:validation:Maximum=1000000
90+
Count *int `json:"count,omitempty"`
91+
92+
// Interval specifies the divisor of the rate of requests, the amount of
93+
// time during which the given count of requests occur.
94+
//
95+
// Support: Extended
96+
// +kubebuilder:validation:XValidation:message="interval can not be greater than one hour",rule="!(duration(self) == duration('0s') || duration(self) > duration('1h'))"
97+
Interval *Duration `json:"interval,omitempty"`
98+
}

apisx/v1alpha1/zz_generated.deepcopy.go

Lines changed: 145 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apisx/v1alpha1/zz_generated.register.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)