1
0
Fork 0

Resync oxy with original repository

This commit is contained in:
SALLEYRON Julien 2017-11-22 18:20:03 +01:00 committed by Traefiker
parent da5e4a13bf
commit bee8ebb00b
31 changed files with 650 additions and 808 deletions

View file

@ -1,4 +1,4 @@
// package cbreaker implements circuit breaker similar to https://github.com/Netflix/Hystrix/wiki/How-it-Works
// Package cbreaker implements circuit breaker similar to https://github.com/Netflix/Hystrix/wiki/How-it-Works
//
// Vulcan circuit breaker watches the error condtion to match
// after which it activates the fallback scenario, e.g. returns the response code
@ -31,6 +31,8 @@ import (
"sync"
"time"
log "github.com/Sirupsen/logrus"
"github.com/mailgun/timetools"
"github.com/vulcand/oxy/memmetrics"
"github.com/vulcand/oxy/utils"
@ -60,7 +62,6 @@ type CircuitBreaker struct {
fallback http.Handler
next http.Handler
log utils.Logger
clock timetools.TimeProvider
}
@ -75,7 +76,6 @@ func New(next http.Handler, expression string, options ...CircuitBreakerOption)
fallbackDuration: defaultFallbackDuration,
recoveryDuration: defaultRecoveryDuration,
fallback: defaultFallback,
log: utils.NullLogger,
}
for _, s := range options {
@ -100,6 +100,11 @@ func New(next http.Handler, expression string, options ...CircuitBreakerOption)
}
func (c *CircuitBreaker) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if log.GetLevel() >= log.DebugLevel {
logEntry := log.WithField("Request", utils.DumpHttpRequest(req))
logEntry.Debug("vulcand/oxy/circuitbreaker: begin ServeHttp on request")
defer logEntry.Debug("vulcand/oxy/circuitbreaker: competed ServeHttp on request")
}
if c.activateFallback(w, req) {
c.fallback.ServeHTTP(w, req)
return
@ -121,7 +126,7 @@ func (c *CircuitBreaker) activateFallback(w http.ResponseWriter, req *http.Reque
c.m.Lock()
defer c.m.Unlock()
c.log.Infof("%v is in error state", c)
log.Infof("%v is in error state", c)
switch c.state {
case stateStandby:
@ -186,13 +191,13 @@ func (c *CircuitBreaker) exec(s SideEffect) {
}
go func() {
if err := s.Exec(); err != nil {
c.log.Errorf("%v side effect failure: %v", c, err)
log.Errorf("%v side effect failure: %v", c, err)
}
}()
}
func (c *CircuitBreaker) setState(new cbState, until time.Time) {
c.log.Infof("%v setting state to %v, until %v", c, new, until)
log.Infof("%v setting state to %v, until %v", c, new, until)
c.state = new
c.until = until
switch new {
@ -225,7 +230,7 @@ func (c *CircuitBreaker) checkAndSet() {
c.lastCheck = c.clock.UtcNow().Add(c.checkPeriod)
if c.state == stateTripped {
c.log.Infof("%v skip set tripped", c)
log.Infof("%v skip set tripped", c)
return
}
@ -309,14 +314,6 @@ func Fallback(h http.Handler) CircuitBreakerOption {
}
}
// Logger adds logging for the CircuitBreaker.
func Logger(l utils.Logger) CircuitBreakerOption {
return func(c *CircuitBreaker) error {
c.log = l
return nil
}
}
// cbState is the state of the circuit breaker
type cbState int

View file

@ -9,6 +9,7 @@ import (
"net/url"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/vulcand/oxy/utils"
)
@ -68,9 +69,10 @@ func (w *WebhookSideEffect) Exec() error {
if re.Body != nil {
defer re.Body.Close()
}
_, err = ioutil.ReadAll(re.Body)
body, err := ioutil.ReadAll(re.Body)
if err != nil {
return err
}
log.Infof("%v got response: (%s): %s", w, re.Status, string(body))
return nil
}

View file

@ -5,6 +5,9 @@ import (
"net/http"
"net/url"
"strconv"
log "github.com/Sirupsen/logrus"
"github.com/vulcand/oxy/utils"
)
type Response struct {
@ -25,20 +28,31 @@ func NewResponseFallback(r Response) (*ResponseFallback, error) {
}
func (f *ResponseFallback) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if log.GetLevel() >= log.DebugLevel {
logEntry := log.WithField("Request", utils.DumpHttpRequest(req))
logEntry.Debug("vulcand/oxy/fallback/response: begin ServeHttp on request")
defer logEntry.Debug("vulcand/oxy/fallback/response: competed ServeHttp on request")
}
if f.r.ContentType != "" {
w.Header().Set("Content-Type", f.r.ContentType)
}
w.Header().Set("Content-Length", strconv.Itoa(len(f.r.Body)))
w.WriteHeader(f.r.StatusCode)
w.Write(f.r.Body)
_, err := w.Write(f.r.Body)
if err != nil {
log.Errorf("vulcand/oxy/fallback/response: failed to write response, err: %v", err)
}
}
type Redirect struct {
URL string
URL string
PreservePath bool
}
type RedirectFallback struct {
u *url.URL
r Redirect
}
func NewRedirectFallback(r Redirect) (*RedirectFallback, error) {
@ -46,11 +60,25 @@ func NewRedirectFallback(r Redirect) (*RedirectFallback, error) {
if err != nil {
return nil, err
}
return &RedirectFallback{u: u}, nil
return &RedirectFallback{u: u, r: r}, nil
}
func (f *RedirectFallback) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Location", f.u.String())
if log.GetLevel() >= log.DebugLevel {
logEntry := log.WithField("Request", utils.DumpHttpRequest(req))
logEntry.Debug("vulcand/oxy/fallback/redirect: begin ServeHttp on request")
defer logEntry.Debug("vulcand/oxy/fallback/redirect: competed ServeHttp on request")
}
location := f.u.String()
if f.r.PreservePath {
location += req.URL.Path
}
w.Header().Set("Location", location)
w.WriteHeader(http.StatusFound)
w.Write([]byte(http.StatusText(http.StatusFound)))
_, err := w.Write([]byte(http.StatusText(http.StatusFound)))
if err != nil {
log.Errorf("vulcand/oxy/fallback/redirect: failed to write response, err: %v", err)
}
}

View file

@ -4,6 +4,7 @@ import (
"fmt"
"time"
log "github.com/Sirupsen/logrus"
"github.com/vulcand/predicate"
)
@ -49,7 +50,7 @@ func latencyAtQuantile(quantile float64) toInt {
return func(c *CircuitBreaker) int {
h, err := c.metrics.LatencyHistogram()
if err != nil {
c.log.Errorf("Failed to get latency histogram, for %v error: %v", c, err)
log.Errorf("Failed to get latency histogram, for %v error: %v", c, err)
return 0
}
return int(h.LatencyAtQuantile(quantile) / time.Millisecond)

View file

@ -4,6 +4,7 @@ import (
"fmt"
"time"
log "github.com/Sirupsen/logrus"
"github.com/mailgun/timetools"
)
@ -33,14 +34,17 @@ func (r *ratioController) String() string {
}
func (r *ratioController) allowRequest() bool {
log.Infof("%v", r)
t := r.targetRatio()
// This condition answers the question - would we satisfy the target ratio if we allow this request?
e := r.computeRatio(r.allowed+1, r.denied)
if e < t {
r.allowed++
log.Infof("%v allowed", r)
return true
}
r.denied++
log.Infof("%v denied", r)
return false
}