1
0
Fork 0

WeightedRoundRobin load balancer

Co-authored-by: Ludovic Fernandez <ldez@users.noreply.github.com>
This commit is contained in:
Julien Salleyron 2019-08-26 10:30:05 +02:00 committed by Traefiker Bot
parent 84de444325
commit 6fed76a687
44 changed files with 1612 additions and 833 deletions

View file

@ -48,7 +48,7 @@ func TestRouterManager_Get(t *testing.T) {
},
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -85,7 +85,7 @@ func TestRouterManager_Get(t *testing.T) {
},
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -108,7 +108,7 @@ func TestRouterManager_Get(t *testing.T) {
},
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -132,7 +132,7 @@ func TestRouterManager_Get(t *testing.T) {
},
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -173,7 +173,7 @@ func TestRouterManager_Get(t *testing.T) {
},
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -213,7 +213,7 @@ func TestRouterManager_Get(t *testing.T) {
},
serviceConfig: map[string]*dynamic.Service{
"foo-service@provider-1": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -236,7 +236,7 @@ func TestRouterManager_Get(t *testing.T) {
},
serviceConfig: map[string]*dynamic.Service{
"foo-service@provider-2": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -260,7 +260,7 @@ func TestRouterManager_Get(t *testing.T) {
},
serviceConfig: map[string]*dynamic.Service{
"foo-service@provider-1": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -355,7 +355,7 @@ func TestAccessLog(t *testing.T) {
},
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -383,7 +383,7 @@ func TestAccessLog(t *testing.T) {
},
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -448,7 +448,7 @@ func TestRuntimeConfiguration(t *testing.T) {
desc: "No error",
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1:8085",
@ -482,7 +482,7 @@ func TestRuntimeConfiguration(t *testing.T) {
desc: "One router with wrong rule",
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -509,7 +509,7 @@ func TestRuntimeConfiguration(t *testing.T) {
desc: "All router with wrong rule",
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -536,7 +536,7 @@ func TestRuntimeConfiguration(t *testing.T) {
desc: "Router with unknown service",
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -579,7 +579,7 @@ func TestRuntimeConfiguration(t *testing.T) {
desc: "Router with middleware",
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -619,7 +619,7 @@ func TestRuntimeConfiguration(t *testing.T) {
desc: "Router with unknown middleware",
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -650,7 +650,7 @@ func TestRuntimeConfiguration(t *testing.T) {
desc: "Router with broken middleware",
serviceConfig: map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -749,7 +749,7 @@ func BenchmarkRouterServe(b *testing.B) {
}
serviceConfig := map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server.URL,
@ -793,7 +793,7 @@ func BenchmarkService(b *testing.B) {
serviceConfig := map[string]*dynamic.Service{
"foo-service": {
LoadBalancer: &dynamic.LoadBalancerService{
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "tchouck",

View file

@ -199,7 +199,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
th.WithRule(routeRule)),
),
th.WithLoadBalancerServices(th.WithService("bar",
th.WithStickiness("test")),
th.WithSticky("test")),
),
)
},
@ -229,7 +229,7 @@ func TestServerResponseEmptyBackend(t *testing.T) {
th.WithRule(routeRule)),
),
th.WithLoadBalancerServices(th.WithService("bar",
th.WithStickiness("test")),
th.WithSticky("test")),
),
)
},

View file

@ -0,0 +1,155 @@
package wrr
import (
"fmt"
"net/http"
"sync"
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/log"
)
type namedHandler struct {
http.Handler
name string
weight int
}
type stickyCookie struct {
name string
secure bool
httpOnly bool
}
// New creates a new load balancer.
func New(sticky *dynamic.Sticky) *Balancer {
balancer := &Balancer{
mutex: &sync.Mutex{},
index: -1,
}
if sticky != nil && sticky.Cookie != nil {
balancer.stickyCookie = &stickyCookie{
name: sticky.Cookie.Name,
secure: sticky.Cookie.Secure,
httpOnly: sticky.Cookie.HTTPOnly,
}
}
return balancer
}
// Balancer is a WeightedRoundRobin load balancer.
type Balancer struct {
handlers []*namedHandler
mutex *sync.Mutex
// Current index (starts from -1)
index int
currentWeight int
stickyCookie *stickyCookie
}
func (b *Balancer) maxWeight() int {
max := -1
for _, s := range b.handlers {
if s.weight > max {
max = s.weight
}
}
return max
}
func (b *Balancer) weightGcd() int {
divisor := -1
for _, s := range b.handlers {
if divisor == -1 {
divisor = s.weight
} else {
divisor = gcd(divisor, s.weight)
}
}
return divisor
}
func gcd(a, b int) int {
for b != 0 {
a, b = b, a%b
}
return a
}
func (b *Balancer) nextServer() (*namedHandler, error) {
b.mutex.Lock()
defer b.mutex.Unlock()
if len(b.handlers) == 0 {
return nil, fmt.Errorf("no servers in the pool")
}
// The algo below may look messy, but is actually very simple
// it calculates the GCD and subtracts it on every iteration, what interleaves servers
// and allows us not to build an iterator every time we readjust weights
// GCD across all enabled servers
gcd := b.weightGcd()
// Maximum weight across all enabled servers
max := b.maxWeight()
for {
b.index = (b.index + 1) % len(b.handlers)
if b.index == 0 {
b.currentWeight -= gcd
if b.currentWeight <= 0 {
b.currentWeight = max
if b.currentWeight == 0 {
return nil, fmt.Errorf("all servers have 0 weight")
}
}
}
srv := b.handlers[b.index]
if srv.weight >= b.currentWeight {
log.WithoutContext().Debugf("Service Select: %s", srv.name)
return srv, nil
}
}
}
func (b *Balancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if b.stickyCookie != nil {
cookie, err := req.Cookie(b.stickyCookie.name)
if err != nil && err != http.ErrNoCookie {
log.WithoutContext().Warnf("Error while reading cookie: %v", err)
}
if err == nil && cookie != nil {
for _, handler := range b.handlers {
if handler.name == cookie.Value {
handler.ServeHTTP(w, req)
return
}
}
}
}
server, err := b.nextServer()
if err != nil {
http.Error(w, http.StatusText(http.StatusInternalServerError)+err.Error(), http.StatusInternalServerError)
return
}
if b.stickyCookie != nil {
cookie := &http.Cookie{Name: b.stickyCookie.name, Value: server.name, Path: "/", HttpOnly: b.stickyCookie.httpOnly, Secure: b.stickyCookie.secure}
http.SetCookie(w, cookie)
}
server.ServeHTTP(w, req)
}
// AddService adds a handler.
// It is not thread safe with ServeHTTP.
func (b *Balancer) AddService(name string, handler http.Handler, weight *int) {
w := 1
if weight != nil {
w = *weight
}
b.handlers = append(b.handlers, &namedHandler{Handler: handler, name: name, weight: w})
}

View file

@ -0,0 +1,115 @@
package wrr
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/stretchr/testify/assert"
)
func Int(v int) *int { return &v }
type responseRecorder struct {
*httptest.ResponseRecorder
save map[string]int
}
func (r *responseRecorder) WriteHeader(statusCode int) {
r.save[r.Header().Get("server")]++
r.ResponseRecorder.WriteHeader(statusCode)
}
func TestBalancer(t *testing.T) {
balancer := New(nil)
balancer.AddService("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "first")
rw.WriteHeader(http.StatusOK)
}), Int(3))
balancer.AddService("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "second")
rw.WriteHeader(http.StatusOK)
}), Int(1))
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
for i := 0; i < 4; i++ {
balancer.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))
}
assert.Equal(t, 3, recorder.save["first"])
assert.Equal(t, 1, recorder.save["second"])
}
func TestBalancerNoService(t *testing.T) {
balancer := New(nil)
recorder := httptest.NewRecorder()
balancer.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))
assert.Equal(t, http.StatusInternalServerError, recorder.Result().StatusCode)
}
func TestBalancerOneServerZeroWeight(t *testing.T) {
balancer := New(nil)
balancer.AddService("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "first")
rw.WriteHeader(http.StatusOK)
}), Int(1))
balancer.AddService("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), Int(0))
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
for i := 0; i < 3; i++ {
balancer.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))
}
assert.Equal(t, 3, recorder.save["first"])
}
func TestBalancerAllServersZeroWeight(t *testing.T) {
balancer := New(nil)
balancer.AddService("test", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), Int(0))
balancer.AddService("test2", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), Int(0))
recorder := httptest.NewRecorder()
balancer.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))
assert.Equal(t, http.StatusInternalServerError, recorder.Result().StatusCode)
}
func TestSticky(t *testing.T) {
balancer := New(&dynamic.Sticky{
Cookie: &dynamic.Cookie{Name: "test"},
})
balancer.AddService("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "first")
rw.WriteHeader(http.StatusOK)
}), Int(1))
balancer.AddService("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "second")
rw.WriteHeader(http.StatusOK)
}), Int(2))
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
req := httptest.NewRequest(http.MethodGet, "/", nil)
for i := 0; i < 3; i++ {
for _, cookie := range recorder.Result().Cookies() {
req.AddCookie(cookie)
}
recorder.ResponseRecorder = httptest.NewRecorder()
balancer.ServeHTTP(recorder, req)
}
assert.Equal(t, 0, recorder.save["first"])
assert.Equal(t, 3, recorder.save["second"])
}

View file

@ -2,6 +2,7 @@ package service
import (
"context"
"errors"
"fmt"
"net/http"
"net/http/httputil"
@ -20,6 +21,7 @@ import (
"github.com/containous/traefik/v2/pkg/middlewares/pipelining"
"github.com/containous/traefik/v2/pkg/server/cookie"
"github.com/containous/traefik/v2/pkg/server/internal"
"github.com/containous/traefik/v2/pkg/server/service/loadbalancer/wrr"
"github.com/vulcand/oxy/roundrobin"
)
@ -60,27 +62,58 @@ func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string, respons
return nil, fmt.Errorf("the service %q does not exist", serviceName)
}
// TODO Should handle multiple service types
// FIXME Check if the service is declared multiple times with different types
if conf.LoadBalancer == nil {
sErr := fmt.Errorf("the service %q doesn't have any load balancer", serviceName)
conf.AddError(sErr, true)
return nil, sErr
if conf.LoadBalancer != nil && conf.Weighted != nil {
return nil, errors.New("cannot create service: multi-types service not supported, consider declaring two different pieces of service instead")
}
lb, err := m.getLoadBalancerServiceHandler(ctx, serviceName, conf.LoadBalancer, responseModifier)
if err != nil {
conf.AddError(err, true)
return nil, err
var lb http.Handler
switch {
case conf.LoadBalancer != nil:
var err error
lb, err = m.getLoadBalancerServiceHandler(ctx, serviceName, conf.LoadBalancer, responseModifier)
if err != nil {
conf.AddError(err, true)
return nil, err
}
case conf.Weighted != nil:
var err error
lb, err = m.getLoadBalancerWRRServiceHandler(ctx, serviceName, conf.Weighted, responseModifier)
if err != nil {
conf.AddError(err, true)
return nil, err
}
default:
sErr := fmt.Errorf("the service %q does not have any type defined", serviceName)
conf.AddError(sErr, true)
return nil, sErr
}
return lb, nil
}
func (m *Manager) getLoadBalancerWRRServiceHandler(ctx context.Context, serviceName string, config *dynamic.WeightedRoundRobin, responseModifier func(*http.Response) error) (http.Handler, error) {
// TODO Handle accesslog and metrics with multiple service name
if config.Sticky != nil && config.Sticky.Cookie != nil {
config.Sticky.Cookie.Name = cookie.GetName(config.Sticky.Cookie.Name, serviceName)
}
balancer := wrr.New(config.Sticky)
for _, service := range config.Services {
serviceHandler, err := m.BuildHTTP(ctx, service.Name, responseModifier)
if err != nil {
return nil, err
}
balancer.AddService(service.Name, serviceHandler, service.Weight)
}
return balancer, nil
}
func (m *Manager) getLoadBalancerServiceHandler(
ctx context.Context,
serviceName string,
service *dynamic.LoadBalancerService,
service *dynamic.ServersLoadBalancer,
responseModifier func(*http.Response) error,
) (http.Handler, error) {
fwd, err := buildProxy(service.PassHostHeader, service.ResponseForwarding, m.defaultRoundTripper, m.bufferPool, responseModifier)
@ -193,16 +226,16 @@ func buildHealthCheckOptions(ctx context.Context, lb healthcheck.BalancerHandler
}
}
func (m *Manager) getLoadBalancer(ctx context.Context, serviceName string, service *dynamic.LoadBalancerService, fwd http.Handler) (healthcheck.BalancerHandler, error) {
func (m *Manager) getLoadBalancer(ctx context.Context, serviceName string, service *dynamic.ServersLoadBalancer, fwd http.Handler) (healthcheck.BalancerHandler, error) {
logger := log.FromContext(ctx)
logger.Debug("Creating load-balancer")
var options []roundrobin.LBOption
var cookieName string
if stickiness := service.Stickiness; stickiness != nil {
cookieName = cookie.GetName(stickiness.CookieName, serviceName)
opts := roundrobin.CookieOptions{HTTPOnly: stickiness.HTTPOnlyCookie, Secure: stickiness.SecureCookie}
if service.Sticky != nil && service.Sticky.Cookie != nil {
cookieName = cookie.GetName(service.Sticky.Cookie.Name, serviceName)
opts := roundrobin.CookieOptions{HTTPOnly: service.Sticky.Cookie.HTTPOnly, Secure: service.Sticky.Cookie.Secure}
options = append(options, roundrobin.EnableStickySession(roundrobin.NewStickySessionWithOptions(cookieName, opts)))
logger.Debugf("Sticky session cookie name: %v", cookieName)
}

View file

@ -27,14 +27,14 @@ func TestGetLoadBalancer(t *testing.T) {
testCases := []struct {
desc string
serviceName string
service *dynamic.LoadBalancerService
service *dynamic.ServersLoadBalancer
fwd http.Handler
expectError bool
}{
{
desc: "Fails when provided an invalid URL",
serviceName: "test",
service: &dynamic.LoadBalancerService{
service: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: ":",
@ -47,15 +47,15 @@ func TestGetLoadBalancer(t *testing.T) {
{
desc: "Succeeds when there are no servers",
serviceName: "test",
service: &dynamic.LoadBalancerService{},
service: &dynamic.ServersLoadBalancer{},
fwd: &MockForwarder{},
expectError: false,
},
{
desc: "Succeeds when stickiness is set",
desc: "Succeeds when sticky.cookie is set",
serviceName: "test",
service: &dynamic.LoadBalancerService{
Stickiness: &dynamic.Stickiness{},
service: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
},
fwd: &MockForwarder{},
expectError: false,
@ -114,7 +114,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
testCases := []struct {
desc string
serviceName string
service *dynamic.LoadBalancerService
service *dynamic.ServersLoadBalancer
responseModifier func(*http.Response) error
expected []ExpectedResult
@ -122,7 +122,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
{
desc: "Load balances between the two servers",
serviceName: "test",
service: &dynamic.LoadBalancerService{
service: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: server1.URL,
@ -146,7 +146,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
{
desc: "StatusBadGateway when the server is not reachable",
serviceName: "test",
service: &dynamic.LoadBalancerService{
service: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://foo",
@ -162,7 +162,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
{
desc: "ServiceUnavailable when no servers are available",
serviceName: "test",
service: &dynamic.LoadBalancerService{
service: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{},
},
expected: []ExpectedResult{
@ -172,10 +172,10 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
},
},
{
desc: "Always call the same server when stickiness is true",
desc: "Always call the same server when sticky.cookie is true",
serviceName: "test",
service: &dynamic.LoadBalancerService{
Stickiness: &dynamic.Stickiness{},
service: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
Servers: []dynamic.Server{
{
URL: server1.URL,
@ -199,8 +199,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
{
desc: "Sticky Cookie's options set correctly",
serviceName: "test",
service: &dynamic.LoadBalancerService{
Stickiness: &dynamic.Stickiness{HTTPOnlyCookie: true, SecureCookie: true},
service: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{HTTPOnly: true, Secure: true}},
Servers: []dynamic.Server{
{
URL: server1.URL,
@ -219,8 +219,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
{
desc: "PassHost passes the host instead of the IP",
serviceName: "test",
service: &dynamic.LoadBalancerService{
Stickiness: &dynamic.Stickiness{},
service: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
PassHostHeader: true,
Servers: []dynamic.Server{
{
@ -238,8 +238,8 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
{
desc: "PassHost doesn't passe the host instead of the IP",
serviceName: "test",
service: &dynamic.LoadBalancerService{
Stickiness: &dynamic.Stickiness{},
service: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
Servers: []dynamic.Server{
{
URL: serverPassHostFalse.URL,
@ -297,7 +297,7 @@ func TestManager_Build(t *testing.T) {
configs: map[string]*runtime.ServiceInfo{
"serviceName": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.LoadBalancerService{},
LoadBalancer: &dynamic.ServersLoadBalancer{},
},
},
},
@ -308,7 +308,7 @@ func TestManager_Build(t *testing.T) {
configs: map[string]*runtime.ServiceInfo{
"serviceName@provider-1": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.LoadBalancerService{},
LoadBalancer: &dynamic.ServersLoadBalancer{},
},
},
},
@ -319,7 +319,7 @@ func TestManager_Build(t *testing.T) {
configs: map[string]*runtime.ServiceInfo{
"serviceName@provider-1": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.LoadBalancerService{},
LoadBalancer: &dynamic.ServersLoadBalancer{},
},
},
},