Rework servers load-balancer to use the WRR

Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
This commit is contained in:
Julien Salleyron 2022-11-16 11:38:07 +01:00 committed by GitHub
parent 67d9c8da0b
commit fadee5e87b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
70 changed files with 2085 additions and 2211 deletions

View file

@ -21,9 +21,8 @@ import (
// Compile time validation that the response recorder implements http interfaces correctly.
var (
// TODO: maybe remove at least for codeModifierWithCloseNotify.
_ middlewares.Stateful = &codeModifierWithCloseNotify{}
_ middlewares.Stateful = &codeCatcherWithCloseNotify{}
_ middlewares.Stateful = &codeModifier{}
_ middlewares.Stateful = &codeCatcher{}
)
const typeName = "customError"
@ -124,13 +123,6 @@ func newRequest(baseURL string) (*http.Request, error) {
return req, nil
}
type responseInterceptor interface {
http.ResponseWriter
http.Flusher
getCode() int
isFilteredCode() bool
}
// codeCatcher is a response writer that detects as soon as possible whether the
// response is a code within the ranges of codes it watches for. If it is, it
// simply drops the data from the response. Otherwise, it forwards it directly to
@ -144,27 +136,13 @@ type codeCatcher struct {
headersSent bool
}
type codeCatcherWithCloseNotify struct {
*codeCatcher
}
// CloseNotify returns a channel that receives at most a
// single value (true) when the client connection has gone away.
func (cc *codeCatcherWithCloseNotify) CloseNotify() <-chan bool {
return cc.responseWriter.(http.CloseNotifier).CloseNotify()
}
func newCodeCatcher(rw http.ResponseWriter, httpCodeRanges types.HTTPCodeRanges) responseInterceptor {
catcher := &codeCatcher{
func newCodeCatcher(rw http.ResponseWriter, httpCodeRanges types.HTTPCodeRanges) *codeCatcher {
return &codeCatcher{
headerMap: make(http.Header),
code: http.StatusOK, // If backend does not call WriteHeader on us, we consider it's a 200.
responseWriter: rw,
httpCodeRanges: httpCodeRanges,
}
if _, ok := rw.(http.CloseNotifier); ok {
return &codeCatcherWithCloseNotify{catcher}
}
return catcher
}
func (cc *codeCatcher) Header() http.Header {
@ -240,24 +218,7 @@ func (cc *codeCatcher) Flush() {
// codeModifier forwards a response back to the client,
// while enforcing a given response code.
type codeModifier interface {
http.ResponseWriter
}
// newCodeModifier returns a codeModifier that enforces the given code.
func newCodeModifier(rw http.ResponseWriter, code int) codeModifier {
codeMod := &codeModifierWithoutCloseNotify{
headerMap: make(http.Header),
code: code,
responseWriter: rw,
}
if _, ok := rw.(http.CloseNotifier); ok {
return &codeModifierWithCloseNotify{codeMod}
}
return codeMod
}
type codeModifierWithoutCloseNotify struct {
type codeModifier struct {
code int // the code enforced in the response.
// headerSent is whether the headers have already been sent,
@ -268,18 +229,17 @@ type codeModifierWithoutCloseNotify struct {
responseWriter http.ResponseWriter
}
type codeModifierWithCloseNotify struct {
*codeModifierWithoutCloseNotify
}
// CloseNotify returns a channel that receives at most a
// single value (true) when the client connection has gone away.
func (r *codeModifierWithCloseNotify) CloseNotify() <-chan bool {
return r.responseWriter.(http.CloseNotifier).CloseNotify()
// newCodeModifier returns a codeModifier that enforces the given code.
func newCodeModifier(rw http.ResponseWriter, code int) *codeModifier {
return &codeModifier{
headerMap: make(http.Header),
code: code,
responseWriter: rw,
}
}
// Header returns the response headers.
func (r *codeModifierWithoutCloseNotify) Header() http.Header {
func (r *codeModifier) Header() http.Header {
if r.headerMap == nil {
r.headerMap = make(http.Header)
}
@ -289,14 +249,14 @@ func (r *codeModifierWithoutCloseNotify) Header() http.Header {
// Write calls WriteHeader to send the enforced code,
// then writes the data directly to r.responseWriter.
func (r *codeModifierWithoutCloseNotify) Write(buf []byte) (int, error) {
func (r *codeModifier) Write(buf []byte) (int, error) {
r.WriteHeader(r.code)
return r.responseWriter.Write(buf)
}
// WriteHeader sends the headers, with the enforced code (the code in argument
// is always ignored), if it hasn't already been done.
func (r *codeModifierWithoutCloseNotify) WriteHeader(_ int) {
func (r *codeModifier) WriteHeader(_ int) {
if r.headerSent {
return
}
@ -307,7 +267,7 @@ func (r *codeModifierWithoutCloseNotify) WriteHeader(_ int) {
}
// Hijack hijacks the connection.
func (r *codeModifierWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) {
func (r *codeModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hijacker, ok := r.responseWriter.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("%T is not a http.Hijacker", r.responseWriter)
@ -316,7 +276,7 @@ func (r *codeModifierWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter,
}
// Flush sends any buffered data to the client.
func (r *codeModifierWithoutCloseNotify) Flush() {
func (r *codeModifier) Flush() {
r.WriteHeader(r.code)
if flusher, ok := r.responseWriter.(http.Flusher); ok {

View file

@ -188,50 +188,3 @@ type mockServiceBuilder struct {
func (m *mockServiceBuilder) BuildHTTP(_ context.Context, _ string) (http.Handler, error) {
return m.handler, nil
}
func TestNewResponseRecorder(t *testing.T) {
testCases := []struct {
desc string
rw http.ResponseWriter
expected http.ResponseWriter
}{
{
desc: "Without Close Notify",
rw: httptest.NewRecorder(),
expected: &codeModifierWithoutCloseNotify{},
},
{
desc: "With Close Notify",
rw: &mockRWCloseNotify{},
expected: &codeModifierWithCloseNotify{},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
rec := newCodeModifier(test.rw, 0)
assert.IsType(t, rec, test.expected)
})
}
}
type mockRWCloseNotify struct{}
func (m *mockRWCloseNotify) CloseNotify() <-chan bool {
panic("implement me")
}
func (m *mockRWCloseNotify) Header() http.Header {
panic("implement me")
}
func (m *mockRWCloseNotify) Write([]byte) (int, error) {
panic("implement me")
}
func (m *mockRWCloseNotify) WriteHeader(int) {
panic("implement me")
}