Example #1
0
func (r *Label) Search(ctx context.Context, req *proto.SearchRequest, rsp *proto.SearchResponse) error {
	if req.Limit <= 0 {
		req.Limit = 10
	}

	if req.Offset <= 0 {
		req.Offset = 0
	}

	labels, err := label.Search(req.Service, req.Key, req.Limit, req.Offset)
	if err != nil {
		return errors.InternalServerError("go.micro.srv.router.Label.Search", err.Error())
	}

	rsp.Labels = labels

	return nil
}
Example #2
0
func (r *router) Select(service string) ([]*proto.Service, error) {
	if len(service) == 0 {
		return nil, errors.New("invalid service")
	}

	// TODO: cache records or watch for updates
	services, err := r.r.GetService(service)
	if err != nil {
		return nil, err
	}

	srvLen := len(services)

	if srvLen == 0 {
		return nil, selector.ErrNotFound
	}

	// grab dynamic runtime labels
	// argh all the labels
	// bad bad bad, don't use 1000
	// TODO: fix. also cache
	labels, err := label.Search(service, "", 1000, 0)
	if err != nil {
		return nil, err
	}

	// grab manually defined rules
	// these are overrides to load balancing
	// TODO: cache. also fix
	rules, err := rule.Search(service, "", 1000, 0)
	if err != nil {
		return nil, err
	}

	// TODO: use stats to assign weights to nodes
	// rather than just arbitrary pointer selection

	// get the pointer and increment it
	r.mtx.Lock()
	pointer := r.pointers[service]
	pointer++
	r.pointers[service] = pointer
	r.mtx.Unlock()

	servs := make([]*proto.Service, srvLen)

	// create starting point based on pointer and length of services
	i := pointer % srvLen

	// iterate through the length of the services
	for j := 0; j < srvLen; j++ {
		// if the pointer has dropped past length rotate back through
		if i >= srvLen {
			i = 0
		}

		// apply the label
		label.Apply(labels, services[i])

		// save the service, pass pointer toProto so it can rotate too
		servs[j] = toProto(services[i], pointer)
		i++
	}

	// we've load balanced the nodes
	// now lets strip based on manual overrides

	// TODO: accept label overrides
	// Rules:
	// service A version latest weight 0 priority 0
	// service A version latest weight 100 priority 0 key=foo value=bar
	// if a Select provides the label foo=bar then we'll return it
	// even where previously the weight was set to 0
	var final []*proto.Service

	// TODO: should be provided as params to this method
	userSelectLabels := map[string]string{}

	for _, service := range servs {
		if s := rule.Apply(rules, service, userSelectLabels); s != nil {
			final = append(final, s)
		}
	}

	return final, nil
}