selector: update selector.Select to accept a slice of structs (#1764)
This commit is contained in:
		
							
								
								
									
										1
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.sum
									
									
									
									
									
								
							| @@ -414,6 +414,7 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s | |||||||
| github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= | github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= | ||||||
| github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= | ||||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
|  | github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= | ||||||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ func (r *random) Options() Options { | |||||||
| 	return Options{} | 	return Options{} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *random) Select(routes []*router.Route) (*router.Route, error) { | func (r *random) Select(routes []router.Route) (*router.Route, error) { | ||||||
| 	// we can't select from an empty pool of routes | 	// we can't select from an empty pool of routes | ||||||
| 	if len(routes) == 0 { | 	if len(routes) == 0 { | ||||||
| 		return nil, ErrNoneAvailable | 		return nil, ErrNoneAvailable | ||||||
| @@ -24,14 +24,14 @@ func (r *random) Select(routes []*router.Route) (*router.Route, error) { | |||||||
|  |  | ||||||
| 	// if there is only one route provided we'll select it | 	// if there is only one route provided we'll select it | ||||||
| 	if len(routes) == 1 { | 	if len(routes) == 1 { | ||||||
| 		return routes[0], nil | 		return &routes[0], nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// select a random route from the slice | 	// select a random route from the slice | ||||||
| 	return routes[rand.Intn(len(routes)-1)], nil | 	return &routes[rand.Intn(len(routes)-1)], nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *random) Record(route *router.Route, err error) error { | func (r *random) Record(route router.Route, err error) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ func (r *roundrobin) Options() selector.Options { | |||||||
| 	return selector.Options{} | 	return selector.Options{} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *roundrobin) Select(routes []*router.Route) (*router.Route, error) { | func (r *roundrobin) Select(routes []router.Route) (*router.Route, error) { | ||||||
| 	if len(routes) == 0 { | 	if len(routes) == 0 { | ||||||
| 		return nil, selector.ErrNoneAvailable | 		return nil, selector.ErrNoneAvailable | ||||||
| 	} | 	} | ||||||
| @@ -51,33 +51,27 @@ func (r *roundrobin) Select(routes []*router.Route) (*router.Route, error) { | |||||||
| 		r.routes[hash] = time.Now() | 		r.routes[hash] = time.Now() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// calculate the route hashes once |  | ||||||
| 	hashes := make(map[*router.Route]uint64, len(routes)) |  | ||||||
| 	for _, s := range routes { |  | ||||||
| 		hashes[s] = s.Hash() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// if a route hasn't yet been seen, prioritise it | 	// if a route hasn't yet been seen, prioritise it | ||||||
| 	for srv, hash := range hashes { | 	for _, route := range routes { | ||||||
| 		if _, ok := r.routes[hash]; !ok { | 		if _, ok := r.routes[route.Hash()]; !ok { | ||||||
| 			setLastUsed(hash) | 			setLastUsed(route.Hash()) | ||||||
| 			return srv, nil | 			return &route, nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// sort the services by the time they were last used | 	// sort the services by the time they were last used | ||||||
| 	sort.SliceStable(routes, func(i, j int) bool { | 	sort.SliceStable(routes, func(i, j int) bool { | ||||||
| 		iLastSeen := r.routes[hashes[routes[i]]] | 		iLastSeen := r.routes[routes[i].Hash()] | ||||||
| 		jLastSeen := r.routes[hashes[routes[j]]] | 		jLastSeen := r.routes[routes[j].Hash()] | ||||||
| 		return iLastSeen.UnixNano() < jLastSeen.UnixNano() | 		return iLastSeen.UnixNano() < jLastSeen.UnixNano() | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	// return the route which was last used | 	// return the route which was last used | ||||||
| 	setLastUsed(hashes[routes[0]]) | 	setLastUsed(routes[0].Hash()) | ||||||
| 	return routes[0], nil | 	return &routes[0], nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (r *roundrobin) Record(srv *router.Route, err error) error { | func (r *roundrobin) Record(srv router.Route, err error) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,39 +11,39 @@ import ( | |||||||
| func TestRoundRobin(t *testing.T) { | func TestRoundRobin(t *testing.T) { | ||||||
| 	selector.Tests(t, NewSelector()) | 	selector.Tests(t, NewSelector()) | ||||||
|  |  | ||||||
| 	r1 := &router.Route{Service: "go.micro.service.foo", Address: "127.0.0.1:8000"} | 	r1 := router.Route{Service: "go.micro.service.foo", Address: "127.0.0.1:8000"} | ||||||
| 	r2 := &router.Route{Service: "go.micro.service.foo", Address: "127.0.0.1:8001"} | 	r2 := router.Route{Service: "go.micro.service.foo", Address: "127.0.0.1:8001"} | ||||||
| 	r3 := &router.Route{Service: "go.micro.service.foo", Address: "127.0.0.1:8002"} | 	r3 := router.Route{Service: "go.micro.service.foo", Address: "127.0.0.1:8002"} | ||||||
|  |  | ||||||
| 	sel := NewSelector() | 	sel := NewSelector() | ||||||
|  |  | ||||||
| 	// By passing r1 and r2 first, it forces a set sequence of (r1 => r2 => r3 => r1) | 	// By passing r1 and r2 first, it forces a set sequence of (r1 => r2 => r3 => r1) | ||||||
|  |  | ||||||
| 	r, err := sel.Select([]*router.Route{r1}) | 	r, err := sel.Select([]router.Route{r1}) | ||||||
| 	assert.Nil(t, err, "Error should be nil") | 	assert.Nil(t, err, "Error should be nil") | ||||||
| 	assert.Equal(t, r1, r, "Expected route to be r1") | 	assert.Equal(t, r1, *r, "Expected route to be r1") | ||||||
|  |  | ||||||
| 	r, err = sel.Select([]*router.Route{r2}) | 	r, err = sel.Select([]router.Route{r2}) | ||||||
| 	assert.Nil(t, err, "Error should be nil") | 	assert.Nil(t, err, "Error should be nil") | ||||||
| 	assert.Equal(t, r2, r, "Expected route to be r2") | 	assert.Equal(t, r2, *r, "Expected route to be r2") | ||||||
|  |  | ||||||
| 	// Because r1 and r2 have been recently called, r3 should be chosen | 	// Because r1 and r2 have been recently called, r3 should be chosen | ||||||
|  |  | ||||||
| 	r, err = sel.Select([]*router.Route{r1, r2, r3}) | 	r, err = sel.Select([]router.Route{r1, r2, r3}) | ||||||
| 	assert.Nil(t, err, "Error should be nil") | 	assert.Nil(t, err, "Error should be nil") | ||||||
| 	assert.Equal(t, r3, r, "Expected route to be r3") | 	assert.Equal(t, r3, *r, "Expected route to be r3") | ||||||
|  |  | ||||||
| 	// r1 was called longest ago, so it should be prioritised | 	// r1 was called longest ago, so it should be prioritised | ||||||
|  |  | ||||||
| 	r, err = sel.Select([]*router.Route{r1, r2, r3}) | 	r, err = sel.Select([]router.Route{r1, r2, r3}) | ||||||
| 	assert.Nil(t, err, "Error should be nil") | 	assert.Nil(t, err, "Error should be nil") | ||||||
| 	assert.Equal(t, r1, r, "Expected route to be r1") | 	assert.Equal(t, r1, *r, "Expected route to be r1") | ||||||
|  |  | ||||||
| 	r, err = sel.Select([]*router.Route{r1, r2, r3}) | 	r, err = sel.Select([]router.Route{r1, r2, r3}) | ||||||
| 	assert.Nil(t, err, "Error should be nil") | 	assert.Nil(t, err, "Error should be nil") | ||||||
| 	assert.Equal(t, r2, r, "Expected route to be r2") | 	assert.Equal(t, r2, *r, "Expected route to be r2") | ||||||
|  |  | ||||||
| 	r, err = sel.Select([]*router.Route{r1, r2, r3}) | 	r, err = sel.Select([]router.Route{r1, r2, r3}) | ||||||
| 	assert.Nil(t, err, "Error should be nil") | 	assert.Nil(t, err, "Error should be nil") | ||||||
| 	assert.Equal(t, r3, r, "Expected route to be r3") | 	assert.Equal(t, r3, *r, "Expected route to be r3") | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,9 +21,9 @@ type Selector interface { | |||||||
| 	// Options the selector is using | 	// Options the selector is using | ||||||
| 	Options() Options | 	Options() Options | ||||||
| 	// Select a route from the pool using the strategy | 	// Select a route from the pool using the strategy | ||||||
| 	Select([]*router.Route) (*router.Route, error) | 	Select([]router.Route) (*router.Route, error) | ||||||
| 	// Record the error returned from a route to inform future selection | 	// Record the error returned from a route to inform future selection | ||||||
| 	Record(*router.Route, error) error | 	Record(router.Route, error) error | ||||||
| 	// Close the selector | 	// Close the selector | ||||||
| 	Close() error | 	Close() error | ||||||
| 	// String returns the name of the selector | 	// String returns the name of the selector | ||||||
|   | |||||||
| @@ -9,24 +9,24 @@ import ( | |||||||
|  |  | ||||||
| // Tests runs all the tests against a selector to ensure the implementations are consistent | // Tests runs all the tests against a selector to ensure the implementations are consistent | ||||||
| func Tests(t *testing.T, s Selector) { | func Tests(t *testing.T, s Selector) { | ||||||
| 	r1 := &router.Route{Service: "go.micro.service.foo", Address: "127.0.0.1:8000"} | 	r1 := router.Route{Service: "go.micro.service.foo", Address: "127.0.0.1:8000"} | ||||||
| 	r2 := &router.Route{Service: "go.micro.service.foo", Address: "127.0.0.1:8001"} | 	r2 := router.Route{Service: "go.micro.service.foo", Address: "127.0.0.1:8001"} | ||||||
|  |  | ||||||
| 	t.Run("Select", func(t *testing.T) { | 	t.Run("Select", func(t *testing.T) { | ||||||
| 		t.Run("NoRoutes", func(t *testing.T) { | 		t.Run("NoRoutes", func(t *testing.T) { | ||||||
| 			srv, err := s.Select([]*router.Route{}) | 			srv, err := s.Select([]router.Route{}) | ||||||
| 			assert.Nil(t, srv, "Route should be nil") | 			assert.Nil(t, srv, "Route should be nil") | ||||||
| 			assert.Equal(t, ErrNoneAvailable, err, "Expected error to be none available") | 			assert.Equal(t, ErrNoneAvailable, err, "Expected error to be none available") | ||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
| 		t.Run("OneRoute", func(t *testing.T) { | 		t.Run("OneRoute", func(t *testing.T) { | ||||||
| 			srv, err := s.Select([]*router.Route{r1}) | 			srv, err := s.Select([]router.Route{r1}) | ||||||
| 			assert.Nil(t, err, "Error should be nil") | 			assert.Nil(t, err, "Error should be nil") | ||||||
| 			assert.Equal(t, r1, srv, "Expected the route to be returned") | 			assert.Equal(t, r1, *srv, "Expected the route to be returned") | ||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
| 		t.Run("MultipleRoutes", func(t *testing.T) { | 		t.Run("MultipleRoutes", func(t *testing.T) { | ||||||
| 			srv, err := s.Select([]*router.Route{r1, r2}) | 			srv, err := s.Select([]router.Route{r1, r2}) | ||||||
| 			assert.Nil(t, err, "Error should be nil") | 			assert.Nil(t, err, "Error should be nil") | ||||||
| 			if srv.Address != r1.Address && srv.Address != r2.Address { | 			if srv.Address != r1.Address && srv.Address != r2.Address { | ||||||
| 				t.Errorf("Expected the route to be one of the inputs") | 				t.Errorf("Expected the route to be one of the inputs") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user