Esempio n. 1
0
// Start fsm and create new pirates
func Start() {
	listener = make(chan gotocol.Message) // listener for fsm
	if archaius.Conf.Population < 2 {
		log.Fatal("fsm: can't create less than 2 pirates")
	}
	// create map of channels and a name index to select randoml nodes from
	noodles = make(map[string]chan gotocol.Message, archaius.Conf.Population)
	pnames = make([]string, archaius.Conf.Population) // indexable name list
	log.Println("fsm: population", archaius.Conf.Population, "pirates")
	for i := 1; i <= archaius.Conf.Population; i++ {
		name := names.Make(archaius.Conf.Arch, "atlantic", "bermuda", "blackbeard", "pirate", i)
		noodles[name] = make(chan gotocol.Message)
		go pirate.Start(noodles[name])
	}
	i := 0
	msgcount := 1
	start := time.Now()
	for name, noodle := range noodles {
		pnames[i] = name
		i++
		// tell the pirate it's name and how to talk back to it's fsm
		// this must be the first message the pirate sees
		noodle <- gotocol.Message{gotocol.Hello, listener, time.Now(), gotocol.NilContext(), name}
		if edda.Logchan != nil {
			// tell the pirate to report itself and new edges to the logger
			noodle <- gotocol.Message{gotocol.Inform, edda.Logchan, time.Now(), gotocol.NilContext(), ""}
			msgcount = 2
		}
	}
	log.Println("fsm: Talk amongst yourselves for", archaius.Conf.RunDuration)
	rand.Seed(int64(len(noodles)))
	for _, name := range pnames {
		// for each pirate tell them about two other random pirates
		noodle := noodles[name] // lookup the channel
		// pick a first random pirate to tell this one about
		talkto := pnames[rand.Intn(len(pnames))]
		noodle <- gotocol.Message{gotocol.NameDrop, noodles[talkto], time.Now(), gotocol.NewRequest(), talkto}
		// pick a second random pirate to tell this one about
		talkto = pnames[rand.Intn(len(pnames))]
		noodle <- gotocol.Message{gotocol.NameDrop, noodles[talkto], time.Now(), gotocol.NewRequest(), talkto}
		// anonymously send this pirate a random amount of GoldCoin up to 100
		gold := fmt.Sprintf("%d", rand.Intn(100))
		noodle <- gotocol.Message{gotocol.GoldCoin, nil, time.Now(), gotocol.NewRequest(), gold}
		// tell this pirate to start chatting with friends every 0.1 to 10 secs
		delay := fmt.Sprintf("%dms", 100+rand.Intn(9900))
		noodle <- gotocol.Message{gotocol.Chat, nil, time.Now(), gotocol.NewRequest(), delay}
	}
	msgcount += 4
	d := time.Since(start)
	log.Println("fsm: Delivered", msgcount*len(pnames), "messages in", d)
	shutdown()
}
Esempio n. 2
0
// 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
			}
		}
	}
}
Esempio n. 3
0
// Reload the network from a file
func Reload(arch string) {
	listener = make(chan gotocol.Message) // listener for fsm
	log.Println("fsm reloading from " + arch + ".json")
	g := graphjson.ReadArch(arch)
	pop := 0
	// count how many nodes there are
	for _, element := range g.Graph {
		if element.Node != "" {
			pop++
		}
	}
	archaius.Conf.Population = pop
	// create the map of channels
	noodles = make(map[string]chan gotocol.Message, archaius.Conf.Population)
	// Start all the services
	for _, element := range g.Graph {
		if element.Node != "" && element.Service != "" {
			name := element.Node
			noodles[name] = make(chan gotocol.Message)
			// start the service and tell it it's name
			switch element.Service {
			case "pirate":
				go pirate.Start(noodles[name])
				noodles[name] <- gotocol.Message{gotocol.Hello, listener, time.Now(), gotocol.NilContext(), name}
				if edda.Logchan != nil {
					// tell the pirate to report itself and new edges to the logger
					noodles[name] <- gotocol.Message{gotocol.Inform, edda.Logchan, time.Now(), gotocol.NilContext(), ""}
				}
			default:
				log.Println("fsm: unknown service: " + element.Service)
			}
		}
	}
	// Make all the connections
	for _, element := range g.Graph {
		if element.Edge != "" && element.Source != "" && element.Target != "" {
			noodles[element.Source] <- gotocol.Message{gotocol.NameDrop, noodles[element.Target], time.Now(), gotocol.NewRequest(), element.Target}
			log.Println("Link " + element.Source + " > " + element.Target)
		}
	}
	// send money and start the pirates chatting
	for _, noodle := range noodles {
		// same as below for now, but will save and read back from file later
		// anonymously send this pirate a random amount of GoldCoin up to 100
		gold := fmt.Sprintf("%d", rand.Intn(100))
		noodle <- gotocol.Message{gotocol.GoldCoin, nil, time.Now(), gotocol.NewRequest(), gold}
		// tell this pirate to start chatting with friends every 0.1 to 10 secs
		delay := fmt.Sprintf("%dms", 100+rand.Intn(9900))
		noodle <- gotocol.Message{gotocol.Chat, nil, time.Now(), gotocol.NilContext(), delay}
	}
	shutdown()
}
Esempio n. 4
0
// Start the pirate, all configuration and state is sent via messages
func Start(listener chan gotocol.Message) {
	dunbar := 10 // starting point for how many buddies to remember
	// remember the channel to talk to named buddies
	buddies := make(map[string]chan gotocol.Message, dunbar)
	// remember who sent GoldCoin and how much, to buy favors
	benefactors := make(map[string]int, dunbar)
	var booty int                   // current GoldCoin balance
	var fsm chan gotocol.Message    // remember how to talk back to creator
	var name string                 // remember my name
	var logger chan gotocol.Message // if set, send updates
	var chatrate time.Duration
	hist := collect.NewHist("")
	chatTicker := time.NewTicker(time.Hour)
	chatTicker.Stop()
	for {
		select {
		case msg := <-listener:
			collect.Measure(hist, time.Since(msg.Sent))
			if archaius.Conf.Msglog {
				log.Printf("%v: %v\n", name, msg)
			}
			switch msg.Imposition {
			case gotocol.Hello:
				if name == "" {
					// if I don't have a name yet remember what I've been named
					fsm = msg.ResponseChan // remember how to talk to my namer
					name = msg.Intention   // message body is my name
					hist = collect.NewHist(name)
				}
			case gotocol.Inform:
				// remember where to send updates
				logger = gotocol.InformHandler(msg, name, listener)
			case gotocol.NameDrop:
				// don't remember too many buddies and don't talk to myself
				buddy := msg.Intention // message body is buddy name
				if len(buddies) < dunbar && buddy != name {
					// remember how to talk to this buddy
					buddies[buddy] = msg.ResponseChan // message channel is buddy's listener
					if logger != nil {
						// if it's setup, tell the logger I have a new buddy to talk to
						logger <- gotocol.Message{gotocol.Inform, listener, time.Now(), gotocol.NilContext(), name + " " + buddy}
					}
				}
			case gotocol.Chat:
				// setup the ticker to run at the specified rate
				d, e := time.ParseDuration(msg.Intention)
				if e == nil && d >= time.Millisecond && d <= time.Hour {
					chatrate = d
					chatTicker = time.NewTicker(chatrate)
					// assume we got paid before we started chatting
					rand.Seed(int64(booty))
				}
			case gotocol.GoldCoin:
				var coin int
				_, e := fmt.Sscanf(msg.Intention, "%d", &coin)
				if e == nil && coin > 0 {
					booty += coin
					for name, ch := range buddies {
						if ch == msg.ResponseChan {
							benefactors[name] += coin
						}
					}
				}
			case gotocol.Goodbye:
				if archaius.Conf.Msglog {
					log.Printf("%v: Going away with %v gold coins, chatting every %v\n", name, booty, chatrate)
				}
				gotocol.Message{gotocol.Goodbye, nil, time.Now(), gotocol.NilContext(), name}.GoSend(fsm)
				return
			}
		case <-chatTicker.C:
			if rand.Intn(100) < 50 { // 50% of the time
				// use Namedrop to tell the last buddy about the first
				var firstBuddyName string
				var firstBuddyChan, lastBuddyChan chan gotocol.Message
				if len(buddies) >= 2 {
					for name, ch := range buddies {
						if firstBuddyName == "" {
							firstBuddyName = name
							firstBuddyChan = ch
						} else {
							lastBuddyChan = ch
						}
						gotocol.Message{gotocol.NameDrop, firstBuddyChan, time.Now(), gotocol.NewRequest(), firstBuddyName}.GoSend(lastBuddyChan)
					}
				}
			} else {
				// send a buddy some money
				if booty > 0 {
					donation := rand.Intn(booty)
					luckyNumber := rand.Intn(len(buddies))
					if donation > 0 {
						for _, ch := range buddies {
							if luckyNumber == 0 {
								gotocol.Message{gotocol.GoldCoin, listener, time.Now(), gotocol.NewRequest(), fmt.Sprintf("%d", donation)}.GoSend(ch)
								booty -= donation
								break
							} else {
								luckyNumber--
							}
						}
					}
				}
			}
		}
	}
}
Esempio n. 5
0
// Start the elb, all configuration and state is sent via messages
func Start(listener chan gotocol.Message) {
	dunbar := archaius.Conf.Population
	// remember the channel to talk to microservices
	microservices := make(map[string]chan gotocol.Message, dunbar)
	microindex := make([]chan gotocol.Message, dunbar)
	dependencies := make(map[string]time.Time, dunbar) // dependent services and time last updated
	var netflixoss, requestor chan gotocol.Message     // remember how to talk back to creator
	var name string                                    // remember my name
	eureka := make(map[string]chan gotocol.Message, 3) // service registry per zone
	var chatrate time.Duration
	ep, _ := time.ParseDuration(archaius.Conf.EurekaPoll)
	eurekaTicker := time.NewTicker(ep)
	hist := collect.NewHist("")
	chatTicker := time.NewTicker(time.Hour)
	chatTicker.Stop()
	for {
		select {
		case msg := <-listener:
			collect.Measure(hist, time.Since(msg.Sent))
			if archaius.Conf.Msglog {
				log.Printf("%v: %v\n", name, msg)
			}
			switch msg.Imposition {
			case gotocol.Hello:
				if name == "" {
					// if I don't have a name yet remember what I've been named
					netflixoss = 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] = gotocol.InformHandler(msg, name, listener)
			case gotocol.NameDrop: // cross zone = true
				gotocol.NameDropHandler(&dependencies, &microservices, msg, name, listener, eureka, true)
			case gotocol.Forget:
				// forget a buddy
				gotocol.ForgetHandler(&dependencies, &microservices, msg)
			case gotocol.Chat:
				// setup the ticker to run at the specified rate
				d, e := time.ParseDuration(msg.Intention)
				if e == nil && d >= time.Millisecond && d <= time.Hour {
					chatrate = d
					chatTicker = time.NewTicker(chatrate)
				}
			case gotocol.GetRequest:
				// route the request on to microservices
				requestor = msg.ResponseChan
				// Intention body indicates which service to route to or which key to get
				// need to lookup service by type rather than randomly call one day
				if len(microservices) > 0 {
					if len(microindex) != len(microservices) {
						// rebuild index
						i := 0
						for _, ch := range microservices {
							microindex[i] = ch
							i++
						}
					}
					m := rand.Intn(len(microservices))
					// pass on request to a random service
					gotocol.Message{gotocol.GetRequest, listener, time.Now(), msg.Ctx.NewSpan(), msg.Intention}.GoSend(microindex[m])
				}
			case gotocol.GetResponse:
				// return path from a request, send payload back up
				if requestor != nil {
					gotocol.Message{gotocol.GetResponse, listener, time.Now(), msg.Ctx.NewSpan(), msg.Intention}.GoSend(requestor)
				}
			case gotocol.Put:
				// route the request on to a random dependency
				if len(microservices) > 0 {
					if len(microindex) != len(microservices) {
						// rebuild index
						i := 0
						for _, ch := range microservices {
							microindex[i] = ch
							i++
						}
					}
					m := rand.Intn(len(microservices))
					// pass on request to a random service
					gotocol.Message{gotocol.Put, listener, time.Now(), msg.Ctx.NewSpan(), msg.Intention}.GoSend(microindex[m])
				}
			case gotocol.Goodbye:
				if archaius.Conf.Msglog {
					log.Printf("%v: Going away, chatting every %v\n", name, chatrate)
				}
				gotocol.Message{gotocol.Goodbye, nil, time.Now(), gotocol.NilContext(), name}.GoSend(netflixoss)
				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}
				}
			}
		case <-chatTicker.C:
			if len(microservices) > 0 {
				// build index if needed
				if len(microindex) != len(microservices) {
					i := 0
					for _, ch := range microservices {
						microindex[i] = ch
						i++
					}
				}
				m := rand.Intn(len(microservices))
				// start a request to a random member of this elb
				gotocol.Message{gotocol.GetRequest, listener, time.Now(), gotocol.NewRequest(), name}.GoSend(microindex[m])
			}
		}
	}
}
Esempio n. 6
0
// Start the denominator, all configuration and state is sent via messages
func Start(listener chan gotocol.Message) {
	dunbar := 6 // starting point for how many nodes to remember
	// remember the channel to talk to microservices
	microservices := make(map[string]chan gotocol.Message, dunbar)
	microindex := make([]chan gotocol.Message, dunbar)
	dependencies := make(map[string]time.Time, dunbar)                       // dependent services and time last updated
	var netflixoss chan gotocol.Message                                      // remember how to talk back to creator
	var name string                                                          // remember my name
	hist := collect.NewHist("")                                              // don't know name yet
	eureka := make(map[string]chan gotocol.Message, 3*archaius.Conf.Regions) // service registry per zone and region
	var chatrate time.Duration
	ep, _ := time.ParseDuration(archaius.Conf.EurekaPoll)
	eurekaTicker := time.NewTicker(ep)
	chatTicker := time.NewTicker(time.Hour)
	chatTicker.Stop()
	for {
		select {
		case msg := <-listener:
			collect.Measure(hist, time.Since(msg.Sent))
			if archaius.Conf.Msglog {
				log.Printf("%v: %v\n", name, msg)
			}
			switch msg.Imposition {
			case gotocol.Hello:
				if name == "" {
					// if I don't have a name yet remember what I've been named
					netflixoss = 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] = gotocol.InformHandler(msg, name, listener)
			case gotocol.NameDrop:
				gotocol.NameDropHandler(&dependencies, &microservices, msg, name, listener, eureka)
			case gotocol.Forget:
				// forget a buddy
				gotocol.ForgetHandler(&dependencies, &microservices, msg)
			case gotocol.Chat:
				// setup the ticker to run at the specified rate
				d, e := time.ParseDuration(msg.Intention)
				if e == nil && d >= time.Millisecond && d <= time.Hour {
					chatrate = d
					chatTicker = time.NewTicker(chatrate)
				}
			case gotocol.GetResponse:
				// return path from a request
				// nothing to do at this level
			case gotocol.Goodbye:
				if archaius.Conf.Msglog {
					log.Printf("%v: Going away, was chatting every %v\n", name, chatrate)
				}
				gotocol.Message{gotocol.Goodbye, nil, time.Now(), gotocol.NilContext(), name}.GoSend(netflixoss)
				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}
				}
			}
		case <-chatTicker.C:
			if len(microservices) > 0 {
				// build index if needed
				if len(microindex) != len(microservices) {
					i := 0
					for _, ch := range microservices {
						microindex[i] = ch
						i++
					}
				}
				m := rand.Intn(len(microservices))
				// start a request to a random member of this denominator
				if rand.Intn(2) == 0 {
					gotocol.Message{gotocol.GetRequest, listener, time.Now(), gotocol.NewRequest(), "why?"}.GoSend(microindex[m])
				} else {
					gotocol.Message{gotocol.Put, listener, time.Now(), gotocol.NewRequest(), "remember me"}.GoSend(microindex[m])
				}
			}
		}
	}
}