Add ResponseCode to CircuitBreaker

This commit is contained in:
Fahrzin Hemmati 2024-01-29 01:58:05 -08:00 committed by GitHub
parent 3174c69c66
commit d37ea3e882
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 25 additions and 2 deletions

View file

@ -85,6 +85,7 @@ At specified intervals (`checkPeriod`), the circuit breaker evaluates `expressio
### Open ### Open
While open, the fallback mechanism takes over the normal service calls for a duration of `FallbackDuration`. While open, the fallback mechanism takes over the normal service calls for a duration of `FallbackDuration`.
The fallback mechanism returns a `HTTP 503` (or `ResponseCode`) to the client.
After this duration, it enters the recovering state. After this duration, it enters the recovering state.
### Recovering ### Recovering
@ -179,3 +180,9 @@ The duration for which the circuit breaker will wait before trying to recover (f
_Optional, Default="10s"_ _Optional, Default="10s"_
The duration for which the circuit breaker will try to recover (as soon as it is in recovering state). The duration for which the circuit breaker will try to recover (as soon as it is in recovering state).
### `ResponseCode`
_Optional, Default="503"_
The status code that the circuit breaker will return while it is in the open state.

View file

@ -16,6 +16,7 @@
- "traefik.http.middlewares.middleware05.circuitbreaker.expression=foobar" - "traefik.http.middlewares.middleware05.circuitbreaker.expression=foobar"
- "traefik.http.middlewares.middleware05.circuitbreaker.fallbackduration=42s" - "traefik.http.middlewares.middleware05.circuitbreaker.fallbackduration=42s"
- "traefik.http.middlewares.middleware05.circuitbreaker.recoveryduration=42s" - "traefik.http.middlewares.middleware05.circuitbreaker.recoveryduration=42s"
- "traefik.http.middlewares.middleware05.circuitbreaker.responsecode=42"
- "traefik.http.middlewares.middleware06.compress=true" - "traefik.http.middlewares.middleware06.compress=true"
- "traefik.http.middlewares.middleware06.compress.excludedcontenttypes=foobar, foobar" - "traefik.http.middlewares.middleware06.compress.excludedcontenttypes=foobar, foobar"
- "traefik.http.middlewares.middleware06.compress.includedcontenttypes=foobar, foobar" - "traefik.http.middlewares.middleware06.compress.includedcontenttypes=foobar, foobar"

View file

@ -137,6 +137,7 @@
checkPeriod = "42s" checkPeriod = "42s"
fallbackDuration = "42s" fallbackDuration = "42s"
recoveryDuration = "42s" recoveryDuration = "42s"
responseCode = 42
[http.middlewares.Middleware06] [http.middlewares.Middleware06]
[http.middlewares.Middleware06.compress] [http.middlewares.Middleware06.compress]
excludedContentTypes = ["foobar", "foobar"] excludedContentTypes = ["foobar", "foobar"]

View file

@ -142,6 +142,7 @@ http:
checkPeriod: 42s checkPeriod: 42s
fallbackDuration: 42s fallbackDuration: 42s
recoveryDuration: 42s recoveryDuration: 42s
responseCode: 42
Middleware06: Middleware06:
compress: compress:
excludedContentTypes: excludedContentTypes:

View file

@ -20,6 +20,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `traefik/http/middlewares/Middleware05/circuitBreaker/expression` | `foobar` | | `traefik/http/middlewares/Middleware05/circuitBreaker/expression` | `foobar` |
| `traefik/http/middlewares/Middleware05/circuitBreaker/fallbackDuration` | `42s` | | `traefik/http/middlewares/Middleware05/circuitBreaker/fallbackDuration` | `42s` |
| `traefik/http/middlewares/Middleware05/circuitBreaker/recoveryDuration` | `42s` | | `traefik/http/middlewares/Middleware05/circuitBreaker/recoveryDuration` | `42s` |
| `traefik/http/middlewares/Middleware05/circuitBreaker/responseCode` | `42` |
| `traefik/http/middlewares/Middleware06/compress/excludedContentTypes/0` | `foobar` | | `traefik/http/middlewares/Middleware06/compress/excludedContentTypes/0` | `foobar` |
| `traefik/http/middlewares/Middleware06/compress/excludedContentTypes/1` | `foobar` | | `traefik/http/middlewares/Middleware06/compress/excludedContentTypes/1` | `foobar` |
| `traefik/http/middlewares/Middleware06/compress/includedContentTypes/0` | `foobar` | | `traefik/http/middlewares/Middleware06/compress/includedContentTypes/0` | `foobar` |

View file

@ -1,6 +1,7 @@
package dynamic package dynamic
import ( import (
"net/http"
"time" "time"
ptypes "github.com/traefik/paerser/types" ptypes "github.com/traefik/paerser/types"
@ -141,6 +142,8 @@ type CircuitBreaker struct {
FallbackDuration ptypes.Duration `json:"fallbackDuration,omitempty" toml:"fallbackDuration,omitempty" yaml:"fallbackDuration,omitempty" export:"true"` FallbackDuration ptypes.Duration `json:"fallbackDuration,omitempty" toml:"fallbackDuration,omitempty" yaml:"fallbackDuration,omitempty" export:"true"`
// RecoveryDuration is the duration for which the circuit breaker will try to recover (as soon as it is in recovering state). // RecoveryDuration is the duration for which the circuit breaker will try to recover (as soon as it is in recovering state).
RecoveryDuration ptypes.Duration `json:"recoveryDuration,omitempty" toml:"recoveryDuration,omitempty" yaml:"recoveryDuration,omitempty" export:"true"` RecoveryDuration ptypes.Duration `json:"recoveryDuration,omitempty" toml:"recoveryDuration,omitempty" yaml:"recoveryDuration,omitempty" export:"true"`
// ResponseCode is the status code that the circuit breaker will return while it is in the open state.
ResponseCode int `json:"responseCode,omitempty" toml:"responseCode,omitempty" yaml:"responseCode,omitempty" export:"true"`
} }
// SetDefaults sets the default values on a RateLimit. // SetDefaults sets the default values on a RateLimit.
@ -148,6 +151,7 @@ func (c *CircuitBreaker) SetDefaults() {
c.CheckPeriod = ptypes.Duration(100 * time.Millisecond) c.CheckPeriod = ptypes.Duration(100 * time.Millisecond)
c.FallbackDuration = ptypes.Duration(10 * time.Second) c.FallbackDuration = ptypes.Duration(10 * time.Second)
c.RecoveryDuration = ptypes.Duration(10 * time.Second) c.RecoveryDuration = ptypes.Duration(10 * time.Second)
c.ResponseCode = http.StatusServiceUnavailable
} }
// +k8s:deepcopy-gen=true // +k8s:deepcopy-gen=true

View file

@ -30,6 +30,7 @@ func TestDecodeConfiguration(t *testing.T) {
"traefik.HTTP.Middlewares.Middleware4.circuitbreaker.checkperiod": "1s", "traefik.HTTP.Middlewares.Middleware4.circuitbreaker.checkperiod": "1s",
"traefik.HTTP.Middlewares.Middleware4.circuitbreaker.fallbackduration": "1s", "traefik.HTTP.Middlewares.Middleware4.circuitbreaker.fallbackduration": "1s",
"traefik.HTTP.Middlewares.Middleware4.circuitbreaker.recoveryduration": "1s", "traefik.HTTP.Middlewares.Middleware4.circuitbreaker.recoveryduration": "1s",
"traefik.HTTP.Middlewares.Middleware4.circuitbreaker.responsecode": "403",
"traefik.http.middlewares.Middleware5.digestauth.headerfield": "foobar", "traefik.http.middlewares.Middleware5.digestauth.headerfield": "foobar",
"traefik.http.middlewares.Middleware5.digestauth.realm": "foobar", "traefik.http.middlewares.Middleware5.digestauth.realm": "foobar",
"traefik.http.middlewares.Middleware5.digestauth.removeheader": "true", "traefik.http.middlewares.Middleware5.digestauth.removeheader": "true",
@ -496,6 +497,7 @@ func TestDecodeConfiguration(t *testing.T) {
CheckPeriod: ptypes.Duration(time.Second), CheckPeriod: ptypes.Duration(time.Second),
FallbackDuration: ptypes.Duration(time.Second), FallbackDuration: ptypes.Duration(time.Second),
RecoveryDuration: ptypes.Duration(time.Second), RecoveryDuration: ptypes.Duration(time.Second),
ResponseCode: 403,
}, },
}, },
"Middleware5": { "Middleware5": {
@ -996,6 +998,7 @@ func TestEncodeConfiguration(t *testing.T) {
CheckPeriod: ptypes.Duration(time.Second), CheckPeriod: ptypes.Duration(time.Second),
FallbackDuration: ptypes.Duration(time.Second), FallbackDuration: ptypes.Duration(time.Second),
RecoveryDuration: ptypes.Duration(time.Second), RecoveryDuration: ptypes.Duration(time.Second),
ResponseCode: 404,
}, },
}, },
"Middleware5": { "Middleware5": {
@ -1206,6 +1209,7 @@ func TestEncodeConfiguration(t *testing.T) {
"traefik.HTTP.Middlewares.Middleware4.CircuitBreaker.CheckPeriod": "1000000000", "traefik.HTTP.Middlewares.Middleware4.CircuitBreaker.CheckPeriod": "1000000000",
"traefik.HTTP.Middlewares.Middleware4.CircuitBreaker.FallbackDuration": "1000000000", "traefik.HTTP.Middlewares.Middleware4.CircuitBreaker.FallbackDuration": "1000000000",
"traefik.HTTP.Middlewares.Middleware4.CircuitBreaker.RecoveryDuration": "1000000000", "traefik.HTTP.Middlewares.Middleware4.CircuitBreaker.RecoveryDuration": "1000000000",
"traefik.HTTP.Middlewares.Middleware4.CircuitBreaker.ResponseCode": "404",
"traefik.HTTP.Middlewares.Middleware5.DigestAuth.HeaderField": "foobar", "traefik.HTTP.Middlewares.Middleware5.DigestAuth.HeaderField": "foobar",
"traefik.HTTP.Middlewares.Middleware5.DigestAuth.Realm": "foobar", "traefik.HTTP.Middlewares.Middleware5.DigestAuth.Realm": "foobar",
"traefik.HTTP.Middlewares.Middleware5.DigestAuth.RemoveHeader": "true", "traefik.HTTP.Middlewares.Middleware5.DigestAuth.RemoveHeader": "true",

View file

@ -30,12 +30,14 @@ func New(ctx context.Context, next http.Handler, confCircuitBreaker dynamic.Circ
logger.Debug().Msg("Creating middleware") logger.Debug().Msg("Creating middleware")
logger.Debug().Msgf("Setting up with expression: %s", expression) logger.Debug().Msgf("Setting up with expression: %s", expression)
responseCode := confCircuitBreaker.ResponseCode
cbOpts := []cbreaker.Option{ cbOpts := []cbreaker.Option{
cbreaker.Fallback(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { cbreaker.Fallback(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
tracing.SetStatusErrorf(req.Context(), "blocked by circuit-breaker (%q)", expression) tracing.SetStatusErrorf(req.Context(), "blocked by circuit-breaker (%q)", expression)
rw.WriteHeader(http.StatusServiceUnavailable) rw.WriteHeader(responseCode)
if _, err := rw.Write([]byte(http.StatusText(http.StatusServiceUnavailable))); err != nil { if _, err := rw.Write([]byte(http.StatusText(responseCode))); err != nil {
log.Ctx(req.Context()).Error().Err(err).Send() log.Ctx(req.Context()).Error().Err(err).Send()
} }
})), })),

View file

@ -171,6 +171,7 @@ func Test_buildConfiguration(t *testing.T) {
"traefik/http/middlewares/Middleware04/circuitBreaker/checkPeriod": "1s", "traefik/http/middlewares/Middleware04/circuitBreaker/checkPeriod": "1s",
"traefik/http/middlewares/Middleware04/circuitBreaker/fallbackDuration": "1s", "traefik/http/middlewares/Middleware04/circuitBreaker/fallbackDuration": "1s",
"traefik/http/middlewares/Middleware04/circuitBreaker/recoveryDuration": "1s", "traefik/http/middlewares/Middleware04/circuitBreaker/recoveryDuration": "1s",
"traefik/http/middlewares/Middleware04/circuitBreaker/responseCode": "404",
"traefik/http/middlewares/Middleware07/errors/status/0": "foobar", "traefik/http/middlewares/Middleware07/errors/status/0": "foobar",
"traefik/http/middlewares/Middleware07/errors/status/1": "foobar", "traefik/http/middlewares/Middleware07/errors/status/1": "foobar",
"traefik/http/middlewares/Middleware07/errors/service": "foobar", "traefik/http/middlewares/Middleware07/errors/service": "foobar",
@ -392,6 +393,7 @@ func Test_buildConfiguration(t *testing.T) {
CheckPeriod: ptypes.Duration(time.Second), CheckPeriod: ptypes.Duration(time.Second),
FallbackDuration: ptypes.Duration(time.Second), FallbackDuration: ptypes.Duration(time.Second),
RecoveryDuration: ptypes.Duration(time.Second), RecoveryDuration: ptypes.Duration(time.Second),
ResponseCode: 404,
}, },
}, },
"Middleware05": { "Middleware05": {