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 }