// ForgetHandler removes a buddy from the buddy list func ForgetHandler(dependencies *map[string]time.Time, microservices *map[string]chan Message, msg Message) { microservice := msg.Intention // message body is buddy name to forget if (*microservices)[microservice] != nil { // an existing buddy to forget // forget how to talk to this buddy (*dependencies)[names.Service(microservice)] = msg.Sent // remember when we were told to forget this service delete(*microservices, microservice) } }
// Delete a single node from the given service func Delete(noodles *map[string]chan gotocol.Message, service string) { if service != "" { for node, ch := range *noodles { if names.Service(node) == service { gotocol.Message{gotocol.Goodbye, nil, time.Now(), gotocol.NewRequest(), "chaosmonkey"}.GoSend(ch) log.Println("chaosmonkey delete: " + node) return } } } }
func NameDropHandler(dependencies *map[string]time.Time, microservices *map[string]chan Message, msg Message, name string, listener chan Message, eureka map[string]chan Message, crosszone ...bool) { if msg.ResponseChan == nil { // dependency by service name, needs to be looked up in eureka (*dependencies)[msg.Intention] = msg.Sent // remember it for later for _, ch := range eureka { //log.Println(name + " looking up " + msg.Intention) Send(ch, Message{GetRequest, listener, time.Now(), NilContext, msg.Intention}) } } else { // update dependency with full name and listener channel microservice := msg.Intention // message body is buddy name if len(crosszone) > 0 || names.Zone(name) == names.Zone(microservice) { if microservice != name && (*microservices)[microservice] == nil { // don't talk to myself or record duplicates // remember how to talk to this buddy (*microservices)[microservice] = msg.ResponseChan // message channel is buddy's listener (*dependencies)[names.Service(microservice)] = msg.Sent for _, ch := range eureka { // tell one of the service registries I have a new buddy to talk to so it doesn't get logged more than once Send(ch, Message{Inform, listener, time.Now(), NilContext, name + " " + microservice}) return } } } } }
// Start eureka discovery service and set name directly func Start(listener chan gotocol.Message, name string) { // use a waitgroup so whoever starts eureka can tell it's ready and when stopping that the logs have been flushed Wg.Add(1) defer Wg.Done() var msg gotocol.Message var ok bool hist := collect.NewHist(name) microservices := make(map[string]chan gotocol.Message, archaius.Conf.Dunbar) eurekaservices := make(map[string]chan gotocol.Message, 2) metadata := make(map[string]meta, archaius.Conf.Dunbar) lastrequest := make(map[callback]time.Time) // remember time of last request for a service from this requestor log.Println(name + ": starting") for { msg, ok = <-listener collect.Measure(hist, time.Since(msg.Sent)) if !ok { break // channel was closed } if archaius.Conf.Msglog { log.Printf("%v(backlog %v): %v\n", name, len(listener), msg) } switch msg.Imposition { // used to wire up connections to other eureka nodes only case gotocol.NameDrop: if msg.Intention != name { // don't talk to myself eurekaservices[msg.Intention] = msg.ResponseChan } // for new nodes record the data, replicate and maybe pass on to be logged case gotocol.Put: if microservices[msg.Intention] == nil { // ignore duplicate requests microservices[msg.Intention] = msg.ResponseChan metadata[msg.Intention] = meta{true, msg.Sent} // replicate request, everyone ends up with the same timestamp for state change of this service for _, c := range eurekaservices { gotocol.Message{gotocol.Replicate, msg.ResponseChan, msg.Sent, msg.Intention}.GoSend(c) } if edda.Logchan != nil { edda.Logchan <- msg } } case gotocol.Replicate: if microservices[msg.Intention] == nil { // ignore multiple requests microservices[msg.Intention] = msg.ResponseChan metadata[msg.Intention] = meta{true, msg.Sent} } case gotocol.Inform: // don't store edges in discovery but do log them if edda.Logchan != nil { edda.Logchan <- msg } case gotocol.GetRequest: if msg.Intention == "" { log.Fatal(name + ": empty GetRequest") } if microservices[msg.Intention] != nil { // matched a unique full name gotocol.Message{gotocol.NameDrop, microservices[msg.Intention], time.Now(), msg.Intention}.GoSend(msg.ResponseChan) break } for n, ch := range microservices { // respond with all the online names that match the service component if names.Service(n) == msg.Intention { // if there was an update for the looked up service since last check // log.Printf("%v: matching %v with %v, last: %v metadata: %v\n", name, n, msg.Intention, lastrequest[callback{n, msg.ResponseChan}], metadata[n].registered) if metadata[n].registered.After(lastrequest[callback{n, msg.ResponseChan}]) { if metadata[n].online { gotocol.Message{gotocol.NameDrop, ch, time.Now(), n}.GoSend(msg.ResponseChan) } else { log.Printf("%v:Forget %v\n", name, n) gotocol.Message{gotocol.Forget, ch, time.Now(), n}.GoSend(msg.ResponseChan) } } // remember for next time lastrequest[callback{n, msg.ResponseChan}] = msg.Sent } } case gotocol.Delete: // remove a node if microservices[msg.Intention] != nil { // matched a unique full name metadata[msg.Intention] = meta{false, time.Now()} // replicate request for _, c := range eurekaservices { gotocol.Message{gotocol.Replicate, nil, time.Now(), msg.Intention}.GoSend(c) } if edda.Logchan != nil { edda.Logchan <- msg } } case gotocol.Goodbye: gotocol.Message{gotocol.Goodbye, nil, time.Now(), name}.GoSend(msg.ResponseChan) log.Println(name + ": closing") return } } }