mirror of https://github.com/hashicorp/consul
Add the ability to retry on reset connection to service-routers (#12890)
parent
f650aa0044
commit
13da2c5fad
|
@ -692,6 +692,16 @@ func setupTestVariationDiscoveryChain(
|
||||||
RetryOnConnectFailure: true,
|
RetryOnConnectFailure: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Match: httpMatch(&structs.ServiceRouteHTTPMatch{
|
||||||
|
PathPrefix: "/retry-reset",
|
||||||
|
}),
|
||||||
|
Destination: &structs.ServiceRouteDestination{
|
||||||
|
Service: "retry-reset",
|
||||||
|
NumRetries: 15,
|
||||||
|
RetryOn: []string{"reset"},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Match: httpMatch(&structs.ServiceRouteHTTPMatch{
|
Match: httpMatch(&structs.ServiceRouteHTTPMatch{
|
||||||
PathPrefix: "/retry-codes",
|
PathPrefix: "/retry-codes",
|
||||||
|
@ -704,11 +714,12 @@ func setupTestVariationDiscoveryChain(
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Match: httpMatch(&structs.ServiceRouteHTTPMatch{
|
Match: httpMatch(&structs.ServiceRouteHTTPMatch{
|
||||||
PathPrefix: "/retry-both",
|
PathPrefix: "/retry-all",
|
||||||
}),
|
}),
|
||||||
Destination: &structs.ServiceRouteDestination{
|
Destination: &structs.ServiceRouteDestination{
|
||||||
Service: "retry-both",
|
Service: "retry-all",
|
||||||
RetryOnConnectFailure: true,
|
RetryOnConnectFailure: true,
|
||||||
|
RetryOn: []string{"5xx", "gateway-error", "reset", "connect-failure", "envoy-ratelimited", "retriable-4xx", "refused-stream", "cancelled", "deadline-exceeded", "internal", "resource-exhausted", "unavailable"},
|
||||||
RetryOnStatusCodes: []uint32{401, 409, 451},
|
RetryOnStatusCodes: []uint32{401, 409, 451},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -228,6 +228,12 @@ func (e *ServiceRouterConfigEntry) Validate() error {
|
||||||
if route.Destination.PrefixRewrite != "" && !eligibleForPrefixRewrite {
|
if route.Destination.PrefixRewrite != "" && !eligibleForPrefixRewrite {
|
||||||
return fmt.Errorf("Route[%d] cannot make use of PrefixRewrite without configuring either PathExact or PathPrefix", i)
|
return fmt.Errorf("Route[%d] cannot make use of PrefixRewrite without configuring either PathExact or PathPrefix", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, r := range route.Destination.RetryOn {
|
||||||
|
if !isValidRetryCondition(r) {
|
||||||
|
return fmt.Errorf("Route[%d] contains an invalid retry condition: %q", i, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,6 +257,26 @@ func isValidHTTPMethod(method string) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isValidRetryCondition(retryOn string) bool {
|
||||||
|
switch retryOn {
|
||||||
|
case "5xx",
|
||||||
|
"gateway-error",
|
||||||
|
"reset",
|
||||||
|
"connect-failure",
|
||||||
|
"envoy-ratelimited",
|
||||||
|
"retriable-4xx",
|
||||||
|
"refused-stream",
|
||||||
|
"cancelled",
|
||||||
|
"deadline-exceeded",
|
||||||
|
"internal",
|
||||||
|
"resource-exhausted",
|
||||||
|
"unavailable":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (e *ServiceRouterConfigEntry) CanRead(authz acl.Authorizer) error {
|
func (e *ServiceRouterConfigEntry) CanRead(authz acl.Authorizer) error {
|
||||||
return canReadDiscoveryChain(e, authz)
|
return canReadDiscoveryChain(e, authz)
|
||||||
}
|
}
|
||||||
|
@ -409,6 +435,10 @@ type ServiceRouteDestination struct {
|
||||||
// 4 failure bubbling up to layer 7.
|
// 4 failure bubbling up to layer 7.
|
||||||
RetryOnConnectFailure bool `json:",omitempty" alias:"retry_on_connect_failure"`
|
RetryOnConnectFailure bool `json:",omitempty" alias:"retry_on_connect_failure"`
|
||||||
|
|
||||||
|
// RetryOn allows setting envoy specific conditions when a request should
|
||||||
|
// be automatically retried.
|
||||||
|
RetryOn []string `json:",omitempty" alias:"retry_on"`
|
||||||
|
|
||||||
// RetryOnStatusCodes is a flat list of http response status codes that are
|
// RetryOnStatusCodes is a flat list of http response status codes that are
|
||||||
// eligible for retry. This again should be feasible in any reasonable proxy.
|
// eligible for retry. This again should be feasible in any reasonable proxy.
|
||||||
RetryOnStatusCodes []uint32 `json:",omitempty" alias:"retry_on_status_codes"`
|
RetryOnStatusCodes []uint32 `json:",omitempty" alias:"retry_on_status_codes"`
|
||||||
|
@ -455,7 +485,7 @@ func (e *ServiceRouteDestination) UnmarshalJSON(data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *ServiceRouteDestination) HasRetryFeatures() bool {
|
func (d *ServiceRouteDestination) HasRetryFeatures() bool {
|
||||||
return d.NumRetries > 0 || d.RetryOnConnectFailure || len(d.RetryOnStatusCodes) > 0
|
return d.NumRetries > 0 || d.RetryOnConnectFailure || len(d.RetryOnStatusCodes) > 0 || len(d.RetryOn) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceSplitterConfigEntry defines how incoming requests are split across
|
// ServiceSplitterConfigEntry defines how incoming requests are split across
|
||||||
|
|
|
@ -2054,6 +2054,43 @@ func TestServiceRouterConfigEntry(t *testing.T) {
|
||||||
}))),
|
}))),
|
||||||
validateErr: "Methods contains \"GET\" more than once",
|
validateErr: "Methods contains \"GET\" more than once",
|
||||||
},
|
},
|
||||||
|
////////////////
|
||||||
|
{
|
||||||
|
name: "route with no match with retry condition",
|
||||||
|
entry: makerouter(ServiceRoute{
|
||||||
|
Match: nil,
|
||||||
|
Destination: &ServiceRouteDestination{
|
||||||
|
Service: "other",
|
||||||
|
RetryOn: []string{
|
||||||
|
"5xx",
|
||||||
|
"gateway-error",
|
||||||
|
"reset",
|
||||||
|
"connect-failure",
|
||||||
|
"envoy-ratelimited",
|
||||||
|
"retriable-4xx",
|
||||||
|
"refused-stream",
|
||||||
|
"cancelled",
|
||||||
|
"deadline-exceeded",
|
||||||
|
"internal",
|
||||||
|
"resource-exhausted",
|
||||||
|
"unavailable",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "route with no match with invalid retry condition",
|
||||||
|
entry: makerouter(ServiceRoute{
|
||||||
|
Match: nil,
|
||||||
|
Destination: &ServiceRouteDestination{
|
||||||
|
Service: "other",
|
||||||
|
RetryOn: []string{
|
||||||
|
"invalid-retry-condition",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
validateErr: "contains an invalid retry condition: \"invalid-retry-condition\"",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
@ -2122,3 +2159,22 @@ func TestIsProtocolHTTPLike(t *testing.T) {
|
||||||
assert.True(t, IsProtocolHTTPLike("http2"))
|
assert.True(t, IsProtocolHTTPLike("http2"))
|
||||||
assert.True(t, IsProtocolHTTPLike("grpc"))
|
assert.True(t, IsProtocolHTTPLike("grpc"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsValidRetryCondition(t *testing.T) {
|
||||||
|
assert.False(t, isValidRetryCondition(""))
|
||||||
|
assert.False(t, isValidRetryCondition("retriable-headers"))
|
||||||
|
assert.False(t, isValidRetryCondition("retriable-status-codes"))
|
||||||
|
|
||||||
|
assert.True(t, isValidRetryCondition("5xx"))
|
||||||
|
assert.True(t, isValidRetryCondition("gateway-error"))
|
||||||
|
assert.True(t, isValidRetryCondition("reset"))
|
||||||
|
assert.True(t, isValidRetryCondition("connect-failure"))
|
||||||
|
assert.True(t, isValidRetryCondition("envoy-ratelimited"))
|
||||||
|
assert.True(t, isValidRetryCondition("retriable-4xx"))
|
||||||
|
assert.True(t, isValidRetryCondition("refused-stream"))
|
||||||
|
assert.True(t, isValidRetryCondition("cancelled"))
|
||||||
|
assert.True(t, isValidRetryCondition("deadline-exceeded"))
|
||||||
|
assert.True(t, isValidRetryCondition("internal"))
|
||||||
|
assert.True(t, isValidRetryCondition("resource-exhausted"))
|
||||||
|
assert.True(t, isValidRetryCondition("unavailable"))
|
||||||
|
}
|
||||||
|
|
|
@ -578,25 +578,7 @@ func (s *ResourceGenerator) makeUpstreamRouteForDiscoveryChain(
|
||||||
}
|
}
|
||||||
|
|
||||||
if destination.HasRetryFeatures() {
|
if destination.HasRetryFeatures() {
|
||||||
retryPolicy := &envoy_route_v3.RetryPolicy{}
|
routeAction.Route.RetryPolicy = getRetryPolicyForDestination(destination)
|
||||||
if destination.NumRetries > 0 {
|
|
||||||
retryPolicy.NumRetries = makeUint32Value(int(destination.NumRetries))
|
|
||||||
}
|
|
||||||
|
|
||||||
// The RetryOn magic values come from: https://www.envoyproxy.io/docs/envoy/v1.10.0/configuration/http_filters/router_filter#config-http-filters-router-x-envoy-retry-on
|
|
||||||
if destination.RetryOnConnectFailure {
|
|
||||||
retryPolicy.RetryOn = "connect-failure"
|
|
||||||
}
|
|
||||||
if len(destination.RetryOnStatusCodes) > 0 {
|
|
||||||
if retryPolicy.RetryOn != "" {
|
|
||||||
retryPolicy.RetryOn = retryPolicy.RetryOn + ",retriable-status-codes"
|
|
||||||
} else {
|
|
||||||
retryPolicy.RetryOn = "retriable-status-codes"
|
|
||||||
}
|
|
||||||
retryPolicy.RetriableStatusCodes = destination.RetryOnStatusCodes
|
|
||||||
}
|
|
||||||
|
|
||||||
routeAction.Route.RetryPolicy = retryPolicy
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := injectHeaderManipToRoute(destination, route); err != nil {
|
if err := injectHeaderManipToRoute(destination, route); err != nil {
|
||||||
|
@ -663,6 +645,43 @@ func (s *ResourceGenerator) makeUpstreamRouteForDiscoveryChain(
|
||||||
return host, nil
|
return host, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRetryPolicyForDestination(destination *structs.ServiceRouteDestination) *envoy_route_v3.RetryPolicy {
|
||||||
|
retryPolicy := &envoy_route_v3.RetryPolicy{}
|
||||||
|
if destination.NumRetries > 0 {
|
||||||
|
retryPolicy.NumRetries = makeUint32Value(int(destination.NumRetries))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The RetryOn magic values come from: https://www.envoyproxy.io/docs/envoy/v1.10.0/configuration/http_filters/router_filter#config-http-filters-router-x-envoy-retry-on
|
||||||
|
var retryStrings []string
|
||||||
|
|
||||||
|
if len(destination.RetryOn) > 0 {
|
||||||
|
retryStrings = append(retryStrings, destination.RetryOn...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if destination.RetryOnConnectFailure {
|
||||||
|
// connect-failure can be enabled by either adding connect-failure to the RetryOn list or by using the legacy RetryOnConnectFailure option
|
||||||
|
// Check that it's not already in the RetryOn list, so we don't set it twice
|
||||||
|
connectFailureExists := false
|
||||||
|
for _, r := range retryStrings {
|
||||||
|
if r == "connect-failure" {
|
||||||
|
connectFailureExists = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !connectFailureExists {
|
||||||
|
retryStrings = append(retryStrings, "connect-failure")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(destination.RetryOnStatusCodes) > 0 {
|
||||||
|
retryStrings = append(retryStrings, "retriable-status-codes")
|
||||||
|
retryPolicy.RetriableStatusCodes = destination.RetryOnStatusCodes
|
||||||
|
}
|
||||||
|
|
||||||
|
retryPolicy.RetryOn = strings.Join(retryStrings, ",")
|
||||||
|
|
||||||
|
return retryPolicy
|
||||||
|
}
|
||||||
|
|
||||||
func makeRouteMatchForDiscoveryRoute(discoveryRoute *structs.DiscoveryRoute) *envoy_route_v3.RouteMatch {
|
func makeRouteMatchForDiscoveryRoute(discoveryRoute *structs.DiscoveryRoute) *envoy_route_v3.RouteMatch {
|
||||||
match := discoveryRoute.Definition.Match
|
match := discoveryRoute.Definition.Match
|
||||||
if match == nil || match.IsEmpty() {
|
if match == nil || match.IsEmpty() {
|
||||||
|
|
|
@ -286,6 +286,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/retry-reset"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "retry-reset.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"retryPolicy": {
|
||||||
|
"retryOn": "reset",
|
||||||
|
"numRetries": 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"match": {
|
"match": {
|
||||||
"prefix": "/retry-codes"
|
"prefix": "/retry-codes"
|
||||||
|
@ -305,12 +317,12 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"match": {
|
"match": {
|
||||||
"prefix": "/retry-both"
|
"prefix": "/retry-all"
|
||||||
},
|
},
|
||||||
"route": {
|
"route": {
|
||||||
"cluster": "retry-both.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
"cluster": "retry-all.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
"retryPolicy": {
|
"retryPolicy": {
|
||||||
"retryOn": "connect-failure,retriable-status-codes",
|
"retryOn": "5xx,gateway-error,reset,connect-failure,envoy-ratelimited,retriable-4xx,refused-stream,cancelled,deadline-exceeded,internal,resource-exhausted,unavailable,retriable-status-codes",
|
||||||
"retriableStatusCodes": [
|
"retriableStatusCodes": [
|
||||||
401,
|
401,
|
||||||
409,
|
409,
|
||||||
|
|
|
@ -287,6 +287,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/retry-reset"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "retry-reset.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"retryPolicy": {
|
||||||
|
"retryOn": "reset",
|
||||||
|
"numRetries": 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"match": {
|
"match": {
|
||||||
"prefix": "/retry-codes"
|
"prefix": "/retry-codes"
|
||||||
|
@ -306,12 +318,12 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"match": {
|
"match": {
|
||||||
"prefix": "/retry-both"
|
"prefix": "/retry-all"
|
||||||
},
|
},
|
||||||
"route": {
|
"route": {
|
||||||
"cluster": "retry-both.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
"cluster": "retry-all.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
"retryPolicy": {
|
"retryPolicy": {
|
||||||
"retryOn": "connect-failure,retriable-status-codes",
|
"retryOn": "5xx,gateway-error,reset,connect-failure,envoy-ratelimited,retriable-4xx,refused-stream,cancelled,deadline-exceeded,internal,resource-exhausted,unavailable,retriable-status-codes",
|
||||||
"retriableStatusCodes": [
|
"retriableStatusCodes": [
|
||||||
401,
|
401,
|
||||||
409,
|
409,
|
||||||
|
|
|
@ -287,6 +287,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"match": {
|
||||||
|
"prefix": "/retry-reset"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"cluster": "retry-reset.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
|
"retryPolicy": {
|
||||||
|
"retryOn": "reset",
|
||||||
|
"numRetries": 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"match": {
|
"match": {
|
||||||
"prefix": "/retry-codes"
|
"prefix": "/retry-codes"
|
||||||
|
@ -306,12 +318,12 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"match": {
|
"match": {
|
||||||
"prefix": "/retry-both"
|
"prefix": "/retry-all"
|
||||||
},
|
},
|
||||||
"route": {
|
"route": {
|
||||||
"cluster": "retry-both.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
"cluster": "retry-all.default.dc1.internal.11111111-2222-3333-4444-555555555555.consul",
|
||||||
"retryPolicy": {
|
"retryPolicy": {
|
||||||
"retryOn": "connect-failure,retriable-status-codes",
|
"retryOn": "5xx,gateway-error,reset,connect-failure,envoy-ratelimited,retriable-4xx,refused-stream,cancelled,deadline-exceeded,internal,resource-exhausted,unavailable,retriable-status-codes",
|
||||||
"retriableStatusCodes": [
|
"retriableStatusCodes": [
|
||||||
401,
|
401,
|
||||||
409,
|
409,
|
||||||
|
|
|
@ -72,6 +72,7 @@ type ServiceRouteDestination struct {
|
||||||
NumRetries uint32 `json:",omitempty" alias:"num_retries"`
|
NumRetries uint32 `json:",omitempty" alias:"num_retries"`
|
||||||
RetryOnConnectFailure bool `json:",omitempty" alias:"retry_on_connect_failure"`
|
RetryOnConnectFailure bool `json:",omitempty" alias:"retry_on_connect_failure"`
|
||||||
RetryOnStatusCodes []uint32 `json:",omitempty" alias:"retry_on_status_codes"`
|
RetryOnStatusCodes []uint32 `json:",omitempty" alias:"retry_on_status_codes"`
|
||||||
|
RetryOn []string `json:",omitempty" alias:"retry_on"`
|
||||||
RequestHeaders *HTTPHeaderModifiers `json:",omitempty" alias:"request_headers"`
|
RequestHeaders *HTTPHeaderModifiers `json:",omitempty" alias:"request_headers"`
|
||||||
ResponseHeaders *HTTPHeaderModifiers `json:",omitempty" alias:"response_headers"`
|
ResponseHeaders *HTTPHeaderModifiers `json:",omitempty" alias:"response_headers"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,6 +272,18 @@ func TestAPI_ConfigEntry_DiscoveryChain(t *testing.T) {
|
||||||
NumRetries: 5,
|
NumRetries: 5,
|
||||||
RetryOnConnectFailure: true,
|
RetryOnConnectFailure: true,
|
||||||
RetryOnStatusCodes: []uint32{500, 503, 401},
|
RetryOnStatusCodes: []uint32{500, 503, 401},
|
||||||
|
RetryOn: []string{
|
||||||
|
"gateway-error",
|
||||||
|
"reset",
|
||||||
|
"envoy-ratelimited",
|
||||||
|
"retriable-4xx",
|
||||||
|
"refused-stream",
|
||||||
|
"cancelled",
|
||||||
|
"deadline-exceeded",
|
||||||
|
"internal",
|
||||||
|
"resource-exhausted",
|
||||||
|
"unavailable",
|
||||||
|
},
|
||||||
RequestHeaders: &HTTPHeaderModifiers{
|
RequestHeaders: &HTTPHeaderModifiers{
|
||||||
Set: map[string]string{
|
Set: map[string]string{
|
||||||
"x-foo": "bar",
|
"x-foo": "bar",
|
||||||
|
|
|
@ -68,6 +68,7 @@ config_entries {
|
||||||
destination {
|
destination {
|
||||||
service_subset = "v2"
|
service_subset = "v2"
|
||||||
retry_on_connect_failure = true # TODO: test
|
retry_on_connect_failure = true # TODO: test
|
||||||
|
retry_on = ["reset"] # TODO: test
|
||||||
retry_on_status_codes = [500, 512] # TODO: test
|
retry_on_status_codes = [500, 512] # TODO: test
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -303,7 +303,7 @@ Routes = [
|
||||||
Match{
|
Match{
|
||||||
HTTP {
|
HTTP {
|
||||||
PathPrefix = "/coffees"
|
PathPrefix = "/coffees"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Destination {
|
Destination {
|
||||||
|
@ -311,13 +311,14 @@ Routes = [
|
||||||
RequestTimeout = "10s"
|
RequestTimeout = "10s"
|
||||||
NumRetries = 3
|
NumRetries = 3
|
||||||
RetryOnConnectFailure = true
|
RetryOnConnectFailure = true
|
||||||
|
RetryOn = ["reset"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Match{
|
Match{
|
||||||
HTTP {
|
HTTP {
|
||||||
PathPrefix = "/orders"
|
PathPrefix = "/orders"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Destination {
|
Destination {
|
||||||
|
@ -325,6 +326,7 @@ Routes = [
|
||||||
RequestTimeout = "10s"
|
RequestTimeout = "10s"
|
||||||
NumRetries = 3
|
NumRetries = 3
|
||||||
RetryOnConnectFailure = true
|
RetryOnConnectFailure = true
|
||||||
|
RetryOn = ["reset"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -345,6 +347,7 @@ spec:
|
||||||
requestTimeout: 10s
|
requestTimeout: 10s
|
||||||
numRetries: 3
|
numRetries: 3
|
||||||
retryOnConnectFailure: true
|
retryOnConnectFailure: true
|
||||||
|
retryOn: ['reset']
|
||||||
- match:
|
- match:
|
||||||
http:
|
http:
|
||||||
pathExact: /orders
|
pathExact: /orders
|
||||||
|
@ -353,7 +356,7 @@ spec:
|
||||||
requestTimeout: 10s
|
requestTimeout: 10s
|
||||||
numRetries: 3
|
numRetries: 3
|
||||||
retryOnConnectFailure: true
|
retryOnConnectFailure: true
|
||||||
|
retryOn: ['reset']
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -372,6 +375,7 @@ spec:
|
||||||
"NumRetries": 3,
|
"NumRetries": 3,
|
||||||
"RequestTimeout": "10s",
|
"RequestTimeout": "10s",
|
||||||
"RetryOnConnectFailure": true,
|
"RetryOnConnectFailure": true,
|
||||||
|
"RetryOn": ["reset"],
|
||||||
"Service": "procurement"
|
"Service": "procurement"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -385,6 +389,7 @@ spec:
|
||||||
"NumRetries": 3,
|
"NumRetries": 3,
|
||||||
"RequestTimeout": "10s",
|
"RequestTimeout": "10s",
|
||||||
"RetryOnConnectFailure": true,
|
"RetryOnConnectFailure": true,
|
||||||
|
"RetryOn": ["reset"],
|
||||||
"Service": "procurement"
|
"Service": "procurement"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -702,6 +707,13 @@ spec:
|
||||||
type: 'bool: false',
|
type: 'bool: false',
|
||||||
description: 'Allows for connection failure errors to trigger a retry.',
|
description: 'Allows for connection failure errors to trigger a retry.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'RetryOn',
|
||||||
|
type: 'array<string>',
|
||||||
|
description: `Allows Consul to retry requests when they meet one of the following sets of conditions:
|
||||||
|
\`5xx\`, \`gateway-error\`, \`reset\`, \`connect-failure\`, \`envoy-ratelimited\`, \`retriable-4xx\`,
|
||||||
|
\`refused-stream\`, \`cancelled\`, \`deadline-exceeded\`, \`internal\`, \`resource-exhausted\`, or \`unavailable\``,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'RetryOnStatusCodes',
|
name: 'RetryOnStatusCodes',
|
||||||
type: 'array<int>',
|
type: 'array<int>',
|
||||||
|
|
Loading…
Reference in New Issue