Example #1
0
// Forget removes a buddy from the buddy list
func Forget(dependencies *map[string]time.Time, router *ribbon.Router, msg gotocol.Message) {
	microservice := msg.Intention          // message body is buddy name to forget
	if router.Named(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
		router.Remove(microservice)
	}
}
Example #2
0
func Put(msg gotocol.Message, name string, listener chan gotocol.Message, requestor *map[string]gotocol.Routetype, router *ribbon.Router) {
	// pass on request to a random service - client send
	c := router.Random()
	if c == nil {
		return
	}
	outmsg := gotocol.Message{gotocol.Put, listener, time.Now(), msg.Ctx.NewParent(), msg.Intention}
	flow.AnnotateSend(outmsg, name)
	outmsg.GoSend(c)
}
Example #3
0
func GetRequest(msg gotocol.Message, name string, listener chan gotocol.Message, requestor *map[string]gotocol.Routetype, router *ribbon.Router) {
	// pass on request to a random service - client send
	c := router.Random()
	if c == nil {
		return
	}
	outmsg := gotocol.Message{gotocol.GetRequest, listener, time.Now(), msg.Ctx.NewParent(), msg.Intention}
	flow.AnnotateSend(outmsg, name)
	(*requestor)[outmsg.Ctx.Route()] = msg.Route() // remember where to respond to when this span comes back
	outmsg.GoSend(c)
}
Example #4
0
// NameDrop updates local buddy list
func NameDrop(dependencies *map[string]time.Time, router *ribbon.Router, msg gotocol.Message, name string, listener chan gotocol.Message, eureka map[string]chan gotocol.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)
			gotocol.Send(ch, gotocol.Message{gotocol.GetRequest, listener, time.Now(), gotocol.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 && router.Named(microservice) == nil { // don't talk to myself or record duplicates
				// remember how to talk to this buddy
				router.Add(microservice, msg.ResponseChan, msg.Sent) // message channel is buddy's listener
				(*dependencies)[names.Service(microservice)] = msg.Sent
				for _, ch := range eureka {
					// tell just one of the service registries I have a new buddy to talk to so it doesn't get logged more than once
					gotocol.Send(ch, gotocol.Message{gotocol.Inform, listener, time.Now(), gotocol.NilContext, name + " " + microservice})
					return
				}
			}
		}
	}
}
Example #5
0
// Start staash, all configuration and state is sent via messages
func Start(listener chan gotocol.Message) {
	microservices := ribbon.MakeRouter()                     // outbound routes
	var caches, stores, volumes, cass, staash *ribbon.Router // subsets of the router
	dependencies := make(map[string]time.Time)               // dependent service names and time last updated
	var parent chan gotocol.Message                          // remember how to talk back to creator
	requestor := make(map[string]gotocol.Routetype)          // remember where requests came from when responding
	var name string                                          // remember my name
	eureka := make(map[string]chan gotocol.Message, 1)       // service registry
	hist := collect.NewHist("")
	ep, _ := time.ParseDuration(archaius.Conf.EurekaPoll)
	eurekaTicker := time.NewTicker(ep)
	for {
		select {
		case msg := <-listener:
			flow.Instrument(msg, name, hist)
			switch msg.Imposition {
			case gotocol.Hello:
				if name == "" {
					// if I don't have a name yet remember what I've been named
					parent = msg.ResponseChan // remember how to talk to my namer
					name = msg.Intention      // message body is my name
					hist = collect.NewHist(name)
				}
			case gotocol.Inform:
				eureka[msg.Intention] = handlers.Inform(msg, name, listener)
			case gotocol.NameDrop:
				handlers.NameDrop(&dependencies, microservices, msg, name, listener, eureka, true) // true to setup cross zone routing
				caches = microservices.All(CachePkg)
				volumes = microservices.All(VolumePkg)
				stores = microservices.All(StorePkg)
				cass = microservices.All(PriamCassandraPkg)
				staash = microservices.All(StaashPkg)
			case gotocol.Forget:
				// forget a buddy
				handlers.Forget(&dependencies, microservices, msg)
				caches = microservices.All(CachePkg)
				volumes = microservices.All(VolumePkg)
				stores = microservices.All(StorePkg)
				cass = microservices.All(PriamCassandraPkg)
				staash = microservices.All(StaashPkg)
			case gotocol.GetRequest:
				// route the request on to a cache first if configured
				r := gotocol.PickRoute(requestor, msg)
				if caches.Len() > 0 {
					handlers.GetRequest(msg, name, listener, &requestor, caches)
					r.State = cacheLookup
				} else {
					// route to any volumes if configured
					if volumes.Len() > 0 {
						handlers.GetRequest(msg, name, listener, &requestor, volumes)
						r.State = volumeLookup
					} else {
						// route to any cassandra if configured
						if cass.Len() > 0 {
							handlers.GetRequest(msg, name, listener, &requestor, cass)
							r.State = cassandraLookup
						} else {
							// route to stores if configured
							if stores.Len() > 0 {
								handlers.GetRequest(msg, name, listener, &requestor, stores)
								r.State = storeLookup
							} else {
								// route to more staash layers if configured
								if staash.Len() > 0 {
									handlers.GetRequest(msg, name, listener, &requestor, staash)
									r.State = staashLookup
								}
							}
						}
					}
				}
				//log.Printf("%v: %v route: %v", name, msg.Context, r)
			case gotocol.GetResponse:
				// return path from a request, resend or send payload back up using saved span context - server send
				r := gotocol.PickRoute(requestor, msg)
				if msg.Intention != "" { // we got a value, so pass it back up
					handlers.GetResponse(msg, name, listener, &requestor)
				} else {
					switch r.State {
					case cacheLookup:
						if volumes.Len() > 0 {
							handlers.GetRequest(msg, name, listener, &requestor, volumes)
							r.State = volumeLookup
							break
						}
						fallthrough // no volumes so look for cassandra
					case volumeLookup:
						if cass.Len() > 0 {
							handlers.GetRequest(msg, name, listener, &requestor, cass)
							r.State = cassandraLookup
							break
						}
						fallthrough // no cassandra so look for stores
					case cassandraLookup:
						if stores.Len() > 0 {
							handlers.GetRequest(msg, name, listener, &requestor, stores)
							r.State = storeLookup
							break
						}
						fallthrough // no stores
					case storeLookup:
						if staash.Len() > 0 {
							handlers.GetRequest(msg, name, listener, &requestor, staash)
							r.State = staashLookup
							break
						}
						fallthrough // no staash
					case staashLookup:
						// ran out of options to find anything so pass empty response back up
						handlers.GetResponse(msg, name, listener, &requestor)
					case newRequest:
					default:
					}
				}
			case gotocol.Put:
				// duplicate the request to any cache, volumes, stores, and cassandra but only to one of each type
				// storage class packages sideways Replicate if configured
				// to get a lossy write, configure multiple stores that don't cross replicate
				handlers.Put(msg, name, listener, &requestor, caches)
				handlers.Put(msg, name, listener, &requestor, cass)
				handlers.Put(msg, name, listener, &requestor, staash)
				handlers.Put(msg, name, listener, &requestor, stores)
				msg.Intention = names.Instance(name) + "/" + msg.Intention // store to an instance specific volume namespace
				handlers.Put(msg, name, listener, &requestor, volumes)
			case gotocol.Goodbye:
				for _, ch := range eureka { // tell name service I'm not going to be here
					ch <- gotocol.Message{gotocol.Delete, nil, time.Now(), gotocol.NilContext, name}
				}
				gotocol.Message{gotocol.Goodbye, nil, time.Now(), gotocol.NilContext, name}.GoSend(parent)
				return
			}
		case <-eurekaTicker.C: // check to see if any new dependencies have appeared
			for dep, _ := range dependencies {
				for _, ch := range eureka {
					ch <- gotocol.Message{gotocol.GetRequest, listener, time.Now(), gotocol.NilContext, dep}
				}
			}
		}
	}
}