Rework servers load-balancer to use the WRR
Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
This commit is contained in:
parent
67d9c8da0b
commit
fadee5e87b
70 changed files with 2085 additions and 2211 deletions
|
@ -10,9 +10,10 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
gokitmetrics "github.com/go-kit/kit/metrics"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/traefik/traefik/v2/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v2/pkg/testhelpers"
|
||||
"github.com/vulcand/oxy/roundrobin"
|
||||
"google.golang.org/grpc"
|
||||
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
||||
)
|
||||
|
@ -64,10 +65,13 @@ func newGRPCServer(healthSequence ...healthpb.HealthCheckResponse_ServingStatus)
|
|||
}
|
||||
|
||||
func (s *GRPCServer) Check(_ context.Context, _ *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) {
|
||||
stat := s.status.Pop()
|
||||
if s.status.IsEmpty() {
|
||||
s.done()
|
||||
return &healthpb.HealthCheckResponse{
|
||||
Status: healthpb.HealthCheckResponse_SERVICE_UNKNOWN,
|
||||
}, nil
|
||||
}
|
||||
stat := s.status.Pop()
|
||||
|
||||
return &healthpb.HealthCheckResponse{
|
||||
Status: stat,
|
||||
|
@ -75,10 +79,13 @@ func (s *GRPCServer) Check(_ context.Context, _ *healthpb.HealthCheckRequest) (*
|
|||
}
|
||||
|
||||
func (s *GRPCServer) Watch(_ *healthpb.HealthCheckRequest, server healthpb.Health_WatchServer) error {
|
||||
stat := s.status.Pop()
|
||||
if s.status.IsEmpty() {
|
||||
s.done()
|
||||
return server.Send(&healthpb.HealthCheckResponse{
|
||||
Status: healthpb.HealthCheckResponse_SERVICE_UNKNOWN,
|
||||
})
|
||||
}
|
||||
stat := s.status.Pop()
|
||||
|
||||
return server.Send(&healthpb.HealthCheckResponse{
|
||||
Status: stat,
|
||||
|
@ -105,7 +112,7 @@ func (s *GRPCServer) Start(t *testing.T, done func()) (*url.URL, time.Duration)
|
|||
}()
|
||||
|
||||
// Make test timeout dependent on number of expected requests, health check interval, and a safety margin.
|
||||
return testhelpers.MustParseURL("http://" + listener.Addr().String()), time.Duration(len(s.status.sequence)*int(healthCheckInterval) + 500)
|
||||
return testhelpers.MustParseURL("http://" + listener.Addr().String()), time.Duration(len(s.status.sequence)*int(dynamic.DefaultHealthCheckInterval) + 500)
|
||||
}
|
||||
|
||||
type HTTPServer struct {
|
||||
|
@ -126,13 +133,14 @@ func newHTTPServer(healthSequence ...int) *HTTPServer {
|
|||
// ServeHTTP returns HTTP response codes following a status sequences.
|
||||
// It calls the given 'done' function once all request health indicators have been depleted.
|
||||
func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, _ *http.Request) {
|
||||
if s.status.IsEmpty() {
|
||||
s.done()
|
||||
return
|
||||
}
|
||||
|
||||
stat := s.status.Pop()
|
||||
|
||||
w.WriteHeader(stat)
|
||||
|
||||
if s.status.IsEmpty() {
|
||||
s.done()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *HTTPServer) Start(t *testing.T, done func()) (*url.URL, time.Duration) {
|
||||
|
@ -144,7 +152,7 @@ func (s *HTTPServer) Start(t *testing.T, done func()) (*url.URL, time.Duration)
|
|||
t.Cleanup(ts.Close)
|
||||
|
||||
// Make test timeout dependent on number of expected requests, health check interval, and a safety margin.
|
||||
return testhelpers.MustParseURL(ts.URL), time.Duration(len(s.status.sequence)*int(healthCheckInterval) + 500)
|
||||
return testhelpers.MustParseURL(ts.URL), time.Duration(len(s.status.sequence)*int(dynamic.DefaultHealthCheckInterval) + 500)
|
||||
}
|
||||
|
||||
type testLoadBalancer struct {
|
||||
|
@ -153,53 +161,20 @@ type testLoadBalancer struct {
|
|||
*sync.RWMutex
|
||||
numRemovedServers int
|
||||
numUpsertedServers int
|
||||
servers []*url.URL
|
||||
// options is just to make sure that LBStatusUpdater forwards options on Upsert to its BalancerHandler
|
||||
options []roundrobin.ServerOption
|
||||
}
|
||||
|
||||
func (lb *testLoadBalancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// noop
|
||||
}
|
||||
|
||||
func (lb *testLoadBalancer) RemoveServer(u *url.URL) error {
|
||||
lb.Lock()
|
||||
defer lb.Unlock()
|
||||
lb.numRemovedServers++
|
||||
lb.removeServer(u)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lb *testLoadBalancer) UpsertServer(u *url.URL, options ...roundrobin.ServerOption) error {
|
||||
lb.Lock()
|
||||
defer lb.Unlock()
|
||||
lb.numUpsertedServers++
|
||||
lb.servers = append(lb.servers, u)
|
||||
lb.options = append(lb.options, options...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lb *testLoadBalancer) Servers() []*url.URL {
|
||||
return lb.servers
|
||||
}
|
||||
|
||||
func (lb *testLoadBalancer) Options() []roundrobin.ServerOption {
|
||||
return lb.options
|
||||
}
|
||||
|
||||
func (lb *testLoadBalancer) removeServer(u *url.URL) {
|
||||
var i int
|
||||
var serverURL *url.URL
|
||||
found := false
|
||||
for i, serverURL = range lb.servers {
|
||||
if *serverURL == *u {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
func (lb *testLoadBalancer) SetStatus(ctx context.Context, childName string, up bool) {
|
||||
if up {
|
||||
lb.numUpsertedServers++
|
||||
} else {
|
||||
lb.numRemovedServers++
|
||||
}
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
lb.servers = append(lb.servers[:i], lb.servers[i+1:]...)
|
||||
}
|
||||
|
||||
type MetricsMock struct {
|
||||
Gauge gokitmetrics.Gauge
|
||||
}
|
||||
|
||||
func (m *MetricsMock) ServiceServerUpGauge() gokitmetrics.Gauge {
|
||||
return m.Gauge
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue