github.com/micro/go-micro/v2@v2.9.1/router/default.go (about)

     1  package router
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/google/uuid"
    12  	"github.com/micro/go-micro/v2/logger"
    13  	"github.com/micro/go-micro/v2/registry"
    14  )
    15  
    16  var (
    17  	// AdvertiseEventsTick is time interval in which the router advertises route updates
    18  	AdvertiseEventsTick = 10 * time.Second
    19  	// DefaultAdvertTTL is default advertisement TTL
    20  	DefaultAdvertTTL = 2 * time.Minute
    21  )
    22  
    23  // router implements default router
    24  type router struct {
    25  	sync.RWMutex
    26  
    27  	running   bool
    28  	table     *table
    29  	options   Options
    30  	exit      chan bool
    31  	eventChan chan *Event
    32  
    33  	// advert subscribers
    34  	sub         sync.RWMutex
    35  	subscribers map[string]chan *Advert
    36  }
    37  
    38  // newRouter creates new router and returns it
    39  func newRouter(opts ...Option) Router {
    40  	// get default options
    41  	options := DefaultOptions()
    42  
    43  	// apply requested options
    44  	for _, o := range opts {
    45  		o(&options)
    46  	}
    47  
    48  	return &router{
    49  		options:     options,
    50  		table:       newTable(),
    51  		subscribers: make(map[string]chan *Advert),
    52  	}
    53  }
    54  
    55  // Init initializes router with given options
    56  func (r *router) Init(opts ...Option) error {
    57  	r.Lock()
    58  	defer r.Unlock()
    59  
    60  	for _, o := range opts {
    61  		o(&r.options)
    62  	}
    63  
    64  	return nil
    65  }
    66  
    67  // Options returns router options
    68  func (r *router) Options() Options {
    69  	r.RLock()
    70  	defer r.RUnlock()
    71  
    72  	options := r.options
    73  
    74  	return options
    75  }
    76  
    77  // Table returns routing table
    78  func (r *router) Table() Table {
    79  	return r.table
    80  }
    81  
    82  // manageRoute applies action on a given route
    83  func (r *router) manageRoute(route Route, action string) error {
    84  	switch action {
    85  	case "create":
    86  		if err := r.table.Create(route); err != nil && err != ErrDuplicateRoute {
    87  			return fmt.Errorf("failed adding route for service %s: %s", route.Service, err)
    88  		}
    89  	case "delete":
    90  		if err := r.table.Delete(route); err != nil && err != ErrRouteNotFound {
    91  			return fmt.Errorf("failed deleting route for service %s: %s", route.Service, err)
    92  		}
    93  	case "update":
    94  		if err := r.table.Update(route); err != nil {
    95  			return fmt.Errorf("failed updating route for service %s: %s", route.Service, err)
    96  		}
    97  	default:
    98  		return fmt.Errorf("failed to manage route for service %s: unknown action %s", route.Service, action)
    99  	}
   100  
   101  	return nil
   102  }
   103  
   104  // manageServiceRoutes applies action to all routes of the service.
   105  // It returns error of the action fails with error.
   106  func (r *router) manageRoutes(service *registry.Service, action string) error {
   107  	// action is the routing table action
   108  	action = strings.ToLower(action)
   109  
   110  	// take route action on each service node
   111  	for _, node := range service.Nodes {
   112  		route := Route{
   113  			Service: service.Name,
   114  			Address: node.Address,
   115  			Gateway: "",
   116  			Network: r.options.Network,
   117  			Router:  r.options.Id,
   118  			Link:    DefaultLink,
   119  			Metric:  DefaultLocalMetric,
   120  		}
   121  
   122  		if err := r.manageRoute(route, action); err != nil {
   123  			return err
   124  		}
   125  	}
   126  
   127  	return nil
   128  }
   129  
   130  // manageRegistryRoutes applies action to all routes of each service found in the registry.
   131  // It returns error if either the services failed to be listed or the routing table action fails.
   132  func (r *router) manageRegistryRoutes(reg registry.Registry, action string) error {
   133  	services, err := reg.ListServices()
   134  	if err != nil {
   135  		return fmt.Errorf("failed listing services: %v", err)
   136  	}
   137  
   138  	// add each service node as a separate route
   139  	for _, service := range services {
   140  		// get the service to retrieve all its info
   141  		srvs, err := reg.GetService(service.Name)
   142  		if err != nil {
   143  			continue
   144  		}
   145  		// manage the routes for all returned services
   146  		for _, srv := range srvs {
   147  			if err := r.manageRoutes(srv, action); err != nil {
   148  				return err
   149  			}
   150  		}
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  // watchRegistry watches registry and updates routing table based on the received events.
   157  // It returns error if either the registry watcher fails with error or if the routing table update fails.
   158  func (r *router) watchRegistry(w registry.Watcher) error {
   159  	exit := make(chan bool)
   160  
   161  	defer func() {
   162  		close(exit)
   163  	}()
   164  
   165  	go func() {
   166  		defer w.Stop()
   167  
   168  		select {
   169  		case <-exit:
   170  			return
   171  		case <-r.exit:
   172  			return
   173  		}
   174  	}()
   175  
   176  	for {
   177  		res, err := w.Next()
   178  		if err != nil {
   179  			if err != registry.ErrWatcherStopped {
   180  				return err
   181  			}
   182  			break
   183  		}
   184  
   185  		if err := r.manageRoutes(res.Service, res.Action); err != nil {
   186  			return err
   187  		}
   188  	}
   189  
   190  	return nil
   191  }
   192  
   193  // watchTable watches routing table entries and either adds or deletes locally registered service to/from network registry
   194  // It returns error if the locally registered services either fails to be added/deleted to/from network registry.
   195  func (r *router) watchTable(w Watcher) error {
   196  	exit := make(chan bool)
   197  
   198  	defer func() {
   199  		close(exit)
   200  	}()
   201  
   202  	// wait in the background for the router to stop
   203  	// when the router stops, stop the watcher and exit
   204  	go func() {
   205  		defer w.Stop()
   206  
   207  		select {
   208  		case <-r.exit:
   209  			return
   210  		case <-exit:
   211  			return
   212  		}
   213  	}()
   214  
   215  	for {
   216  		event, err := w.Next()
   217  		if err != nil {
   218  			if err != ErrWatcherStopped {
   219  				return err
   220  			}
   221  			break
   222  		}
   223  
   224  		select {
   225  		case <-r.exit:
   226  			close(r.eventChan)
   227  			return nil
   228  		case r.eventChan <- event:
   229  			// process event
   230  		}
   231  	}
   232  
   233  	return nil
   234  }
   235  
   236  // publishAdvert publishes router advert to advert channel
   237  func (r *router) publishAdvert(advType AdvertType, events []*Event) {
   238  	a := &Advert{
   239  		Id:        r.options.Id,
   240  		Type:      advType,
   241  		TTL:       DefaultAdvertTTL,
   242  		Timestamp: time.Now(),
   243  		Events:    events,
   244  	}
   245  
   246  	r.sub.RLock()
   247  	for _, sub := range r.subscribers {
   248  		// now send the message
   249  		select {
   250  		case sub <- a:
   251  		case <-r.exit:
   252  			r.sub.RUnlock()
   253  			return
   254  		}
   255  	}
   256  	r.sub.RUnlock()
   257  }
   258  
   259  // adverts maintains a map of router adverts
   260  type adverts map[uint64]*Event
   261  
   262  // advertiseEvents advertises routing table events
   263  // It suppresses unhealthy flapping events and advertises healthy events upstream.
   264  func (r *router) advertiseEvents() error {
   265  	// ticker to periodically scan event for advertising
   266  	ticker := time.NewTicker(AdvertiseEventsTick)
   267  	defer ticker.Stop()
   268  
   269  	// adverts is a map of advert events
   270  	adverts := make(adverts)
   271  
   272  	// routing table watcher
   273  	w, err := r.Watch()
   274  	if err != nil {
   275  		return err
   276  	}
   277  	defer w.Stop()
   278  
   279  	go func() {
   280  		var err error
   281  
   282  		for {
   283  			select {
   284  			case <-r.exit:
   285  				return
   286  			default:
   287  				if w == nil {
   288  					// routing table watcher
   289  					w, err = r.Watch()
   290  					if err != nil {
   291  						if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
   292  							logger.Errorf("Error creating watcher: %v", err)
   293  						}
   294  						time.Sleep(time.Second)
   295  						continue
   296  					}
   297  				}
   298  
   299  				if err := r.watchTable(w); err != nil {
   300  					if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
   301  						logger.Errorf("Error watching table: %v", err)
   302  					}
   303  					time.Sleep(time.Second)
   304  				}
   305  
   306  				if w != nil {
   307  					// reset
   308  					w.Stop()
   309  					w = nil
   310  				}
   311  			}
   312  		}
   313  	}()
   314  
   315  	for {
   316  		select {
   317  		case <-ticker.C:
   318  			// If we're not advertising any events then sip processing them entirely
   319  			if r.options.Advertise == AdvertiseNone {
   320  				continue
   321  			}
   322  
   323  			var events []*Event
   324  
   325  			// collect all events which are not flapping
   326  			for key, event := range adverts {
   327  				// if we only advertise local routes skip processing anything not link local
   328  				if r.options.Advertise == AdvertiseLocal && event.Route.Link != "local" {
   329  					continue
   330  				}
   331  
   332  				// copy the event and append
   333  				e := new(Event)
   334  				// this is ok, because router.Event only contains builtin types
   335  				// and no references so this creates a deep copy of struct Event
   336  				*e = *event
   337  				events = append(events, e)
   338  				// delete the advert from adverts
   339  				delete(adverts, key)
   340  			}
   341  
   342  			// advertise events to subscribers
   343  			if len(events) > 0 {
   344  				if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   345  					logger.Debugf("Router publishing %d events", len(events))
   346  				}
   347  				go r.publishAdvert(RouteUpdate, events)
   348  			}
   349  		case e := <-r.eventChan:
   350  			// if event is nil, continue
   351  			if e == nil {
   352  				continue
   353  			}
   354  
   355  			// If we're not advertising any events then skip processing them entirely
   356  			if r.options.Advertise == AdvertiseNone {
   357  				continue
   358  			}
   359  
   360  			// if we only advertise local routes skip processing anything not link local
   361  			if r.options.Advertise == AdvertiseLocal && e.Route.Link != "local" {
   362  				continue
   363  			}
   364  
   365  			if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   366  				logger.Debugf("Router processing table event %s for service %s %s", e.Type, e.Route.Service, e.Route.Address)
   367  			}
   368  
   369  			// check if we have already registered the route
   370  			hash := e.Route.Hash()
   371  			ev, ok := adverts[hash]
   372  			if !ok {
   373  				ev = e
   374  				adverts[hash] = e
   375  				continue
   376  			}
   377  
   378  			// override the route event only if the previous event was different
   379  			if ev.Type != e.Type {
   380  				ev = e
   381  			}
   382  		case <-r.exit:
   383  			if w != nil {
   384  				w.Stop()
   385  			}
   386  			return nil
   387  		}
   388  	}
   389  }
   390  
   391  // drain all the events, only called on Stop
   392  func (r *router) drain() {
   393  	for {
   394  		select {
   395  		case <-r.eventChan:
   396  		default:
   397  			return
   398  		}
   399  	}
   400  }
   401  
   402  // Start starts the router
   403  func (r *router) Start() error {
   404  	r.Lock()
   405  	defer r.Unlock()
   406  
   407  	if r.running {
   408  		return nil
   409  	}
   410  
   411  	// add all local service routes into the routing table
   412  	if err := r.manageRegistryRoutes(r.options.Registry, "create"); err != nil {
   413  		return fmt.Errorf("failed adding registry routes: %s", err)
   414  	}
   415  
   416  	// add default gateway into routing table
   417  	if r.options.Gateway != "" {
   418  		// note, the only non-default value is the gateway
   419  		route := Route{
   420  			Service: "*",
   421  			Address: "*",
   422  			Gateway: r.options.Gateway,
   423  			Network: "*",
   424  			Router:  r.options.Id,
   425  			Link:    DefaultLink,
   426  			Metric:  DefaultLocalMetric,
   427  		}
   428  		if err := r.table.Create(route); err != nil {
   429  			return fmt.Errorf("failed adding default gateway route: %s", err)
   430  		}
   431  	}
   432  
   433  	// create error and exit channels
   434  	r.exit = make(chan bool)
   435  
   436  	// registry watcher
   437  	w, err := r.options.Registry.Watch()
   438  	if err != nil {
   439  		return fmt.Errorf("failed creating registry watcher: %v", err)
   440  	}
   441  
   442  	go func() {
   443  		var err error
   444  
   445  		for {
   446  			select {
   447  			case <-r.exit:
   448  				if w != nil {
   449  					w.Stop()
   450  				}
   451  				return
   452  			default:
   453  				if w == nil {
   454  					w, err = r.options.Registry.Watch()
   455  					if err != nil {
   456  						if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
   457  							logger.Errorf("failed creating registry watcher: %v", err)
   458  						}
   459  						time.Sleep(time.Second)
   460  						continue
   461  					}
   462  				}
   463  
   464  				if err := r.watchRegistry(w); err != nil {
   465  					if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
   466  						logger.Errorf("Error watching the registry: %v", err)
   467  					}
   468  					time.Sleep(time.Second)
   469  				}
   470  
   471  				if w != nil {
   472  					w.Stop()
   473  					w = nil
   474  				}
   475  			}
   476  		}
   477  	}()
   478  
   479  	r.running = true
   480  
   481  	return nil
   482  }
   483  
   484  // Advertise stars advertising the routes to the network and returns the advertisements channel to consume from.
   485  // If the router is already advertising it returns the channel to consume from.
   486  // It returns error if either the router is not running or if the routing table fails to list the routes to advertise.
   487  func (r *router) Advertise() (<-chan *Advert, error) {
   488  	r.Lock()
   489  	defer r.Unlock()
   490  
   491  	if !r.running {
   492  		return nil, errors.New("not running")
   493  	}
   494  
   495  	// already advertising
   496  	if r.eventChan != nil {
   497  		advertChan := make(chan *Advert, 128)
   498  		r.subscribers[uuid.New().String()] = advertChan
   499  		return advertChan, nil
   500  	}
   501  
   502  	// list all the routes and pack them into even slice to advertise
   503  	events, err := r.flushRouteEvents(Create)
   504  	if err != nil {
   505  		return nil, fmt.Errorf("failed to flush routes: %s", err)
   506  	}
   507  
   508  	// create event channels
   509  	r.eventChan = make(chan *Event)
   510  
   511  	// create advert channel
   512  	advertChan := make(chan *Advert, 128)
   513  	r.subscribers[uuid.New().String()] = advertChan
   514  
   515  	// advertise your presence
   516  	go r.publishAdvert(Announce, events)
   517  
   518  	go func() {
   519  		select {
   520  		case <-r.exit:
   521  			return
   522  		default:
   523  			if err := r.advertiseEvents(); err != nil {
   524  				if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
   525  					logger.Errorf("Error adveritising events: %v", err)
   526  				}
   527  			}
   528  		}
   529  	}()
   530  
   531  	return advertChan, nil
   532  
   533  }
   534  
   535  // Process updates the routing table using the advertised values
   536  func (r *router) Process(a *Advert) error {
   537  	// NOTE: event sorting might not be necessary
   538  	// copy update events intp new slices
   539  	events := make([]*Event, len(a.Events))
   540  	copy(events, a.Events)
   541  	// sort events by timestamp
   542  	sort.Slice(events, func(i, j int) bool {
   543  		return events[i].Timestamp.Before(events[j].Timestamp)
   544  	})
   545  
   546  	if logger.V(logger.TraceLevel, logger.DefaultLogger) {
   547  		logger.Tracef("Router %s processing advert from: %s", r.options.Id, a.Id)
   548  	}
   549  
   550  	for _, event := range events {
   551  		// skip if the router is the origin of this route
   552  		if event.Route.Router == r.options.Id {
   553  			if logger.V(logger.TraceLevel, logger.DefaultLogger) {
   554  				logger.Tracef("Router skipping processing its own route: %s", r.options.Id)
   555  			}
   556  			continue
   557  		}
   558  		// create a copy of the route
   559  		route := event.Route
   560  		action := event.Type
   561  
   562  		if logger.V(logger.TraceLevel, logger.DefaultLogger) {
   563  			logger.Tracef("Router %s applying %s from router %s for service %s %s", r.options.Id, action, route.Router, route.Service, route.Address)
   564  		}
   565  
   566  		if err := r.manageRoute(route, action.String()); err != nil {
   567  			return fmt.Errorf("failed applying action %s to routing table: %s", action, err)
   568  		}
   569  	}
   570  
   571  	return nil
   572  }
   573  
   574  // flushRouteEvents returns a slice of events, one per each route in the routing table
   575  func (r *router) flushRouteEvents(evType EventType) ([]*Event, error) {
   576  	// get a list of routes for each service in our routing table
   577  	// for the configured advertising strategy
   578  	q := []QueryOption{
   579  		QueryStrategy(r.options.Advertise),
   580  	}
   581  
   582  	routes, err := r.Table().Query(q...)
   583  	if err != nil && err != ErrRouteNotFound {
   584  		return nil, err
   585  	}
   586  
   587  	if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   588  		logger.Debugf("Router advertising %d routes with strategy %s", len(routes), r.options.Advertise)
   589  	}
   590  
   591  	// build a list of events to advertise
   592  	events := make([]*Event, len(routes))
   593  	var i int
   594  
   595  	for _, route := range routes {
   596  		event := &Event{
   597  			Type:      evType,
   598  			Timestamp: time.Now(),
   599  			Route:     route,
   600  		}
   601  		events[i] = event
   602  		i++
   603  	}
   604  
   605  	return events, nil
   606  }
   607  
   608  // Lookup routes in the routing table
   609  func (r *router) Lookup(q ...QueryOption) ([]Route, error) {
   610  	return r.table.Query(q...)
   611  }
   612  
   613  // Watch routes
   614  func (r *router) Watch(opts ...WatchOption) (Watcher, error) {
   615  	return r.table.Watch(opts...)
   616  }
   617  
   618  // Stop stops the router
   619  func (r *router) Stop() error {
   620  	r.Lock()
   621  	defer r.Unlock()
   622  
   623  	select {
   624  	case <-r.exit:
   625  		return nil
   626  	default:
   627  		close(r.exit)
   628  
   629  		// extract the events
   630  		r.drain()
   631  
   632  		r.sub.Lock()
   633  		// close advert subscribers
   634  		for id, sub := range r.subscribers {
   635  			// close the channel
   636  			close(sub)
   637  			// delete the subscriber
   638  			delete(r.subscribers, id)
   639  		}
   640  		r.sub.Unlock()
   641  	}
   642  
   643  	// remove event chan
   644  	r.eventChan = nil
   645  
   646  	return nil
   647  }
   648  
   649  // String prints debugging information about router
   650  func (r *router) String() string {
   651  	return "registry"
   652  }