func (rep *LossyRep) vote(guid string, instance instance.Instance, c chan types.VoteResult) { result := types.VoteResult{ Rep: guid, } defer func() { c <- result }() if rep.beSlowAndFlakey(guid) { result.Error = "timeout" return } score, err := rep.reps[guid].Vote(instance) if err != nil { result.Error = err.Error() return } result.Score = score return }
func (rep *RepHTTPClient) vote(guid string, instance instance.Instance, c chan types.VoteResult) { rep.enter() defer rep.exit() result := types.VoteResult{ Rep: guid, } defer func() { c <- result }() body := new(bytes.Buffer) err := json.NewEncoder(body).Encode(instance) if err != nil { result.Error = err.Error() return } resp, err := rep.client.Post(rep.endpoints[guid]+"/vote", "application/json", body) if err != nil { println(err.Error()) result.Error = err.Error() return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { result.Error = "failed" return } var score float64 err = json.NewDecoder(resp.Body).Decode(&score) if err != nil { result.Error = err.Error() return } result.Score = score return }
func Auction(client types.RepPoolClient, auctionRequest types.AuctionRequest) types.AuctionResult { var auctionWinner string var representatives []string if !auctionRequest.Rules.RepickEveryRound { representatives = randomSubset(auctionRequest.RepGuids, auctionRequest.Rules.MaxBiddingPool) } numRounds, numVotes := 0, 0 t := time.Now() for round := 1; round <= auctionRequest.Rules.MaxRounds; round++ { if auctionRequest.Rules.RepickEveryRound { representatives = randomSubset(auctionRequest.RepGuids, auctionRequest.Rules.MaxBiddingPool) } numRounds++ winner, _, err := vote(client, auctionRequest.Instance, representatives) numVotes += len(representatives) if err != nil { continue } c := make(chan types.VoteResult) go func() { winnerScore, err := client.ReserveAndRecastVote(winner, auctionRequest.Instance) result := types.VoteResult{ Rep: winner, } if err != nil { result.Error = err.Error() c <- result return } result.Score = winnerScore c <- result }() secondRoundVoters := []string{} for _, rep := range representatives { if rep != winner { secondRoundVoters = append(secondRoundVoters, rep) } } _, secondPlaceScore, err := vote(client, auctionRequest.Instance, secondRoundVoters) winnerRecast := <-c numVotes += len(representatives) if winnerRecast.Error != "" { //winner ran out of space on the recast, retry continue } if err == nil && secondPlaceScore < winnerRecast.Score && round < auctionRequest.Rules.MaxRounds { client.Release(winner, auctionRequest.Instance) continue } client.Claim(winner, auctionRequest.Instance) auctionWinner = winner break } return types.AuctionResult{ Winner: auctionWinner, Instance: auctionRequest.Instance, NumRounds: numRounds, NumVotes: numVotes, Duration: time.Since(t), } }
func Start(natsAddrs []string, rep *representative.Representative) { client := yagnats.NewClient() clusterInfo := &yagnats.ConnectionCluster{} for _, addr := range natsAddrs { clusterInfo.Members = append(clusterInfo.Members, &yagnats.ConnectionInfo{ Addr: addr, }) } err := client.Connect(clusterInfo) if err != nil { log.Fatalln("no nats:", err) } guid := rep.Guid() client.Subscribe(guid+".guid", func(msg *yagnats.Message) { jguid, _ := json.Marshal(rep.Guid()) client.Publish(msg.ReplyTo, jguid) }) client.Subscribe(guid+".total_resources", func(msg *yagnats.Message) { jresources, _ := json.Marshal(rep.TotalResources()) client.Publish(msg.ReplyTo, jresources) }) client.Subscribe(guid+".reset", func(msg *yagnats.Message) { rep.Reset() client.Publish(msg.ReplyTo, successResponse) }) client.Subscribe(guid+".set_instances", func(msg *yagnats.Message) { var instances []instance.Instance err := json.Unmarshal(msg.Payload, &instances) if err != nil { client.Publish(msg.ReplyTo, errorResponse) } rep.SetInstances(instances) client.Publish(msg.ReplyTo, successResponse) }) client.Subscribe(guid+".instances", func(msg *yagnats.Message) { jinstances, _ := json.Marshal(rep.Instances()) client.Publish(msg.ReplyTo, jinstances) }) client.Subscribe(guid+".vote", func(msg *yagnats.Message) { var inst instance.Instance err := json.Unmarshal(msg.Payload, &inst) if err != nil { panic(err) } response := types.VoteResult{ Rep: guid, } defer func() { payload, _ := json.Marshal(response) client.Publish(msg.ReplyTo, payload) }() score, err := rep.Vote(inst) if err != nil { // log.Println(guid, "failed to vote:", err) response.Error = err.Error() return } response.Score = score }) client.Subscribe(guid+".reserve_and_recast_vote", func(msg *yagnats.Message) { var inst instance.Instance responsePayload := errorResponse defer func() { client.Publish(msg.ReplyTo, responsePayload) }() err := json.Unmarshal(msg.Payload, &inst) if err != nil { // log.Println(guid, "invalid reserve_and_recast_vote request:", err) return } score, err := rep.ReserveAndRecastVote(inst) if err != nil { // log.Println(guid, "failed to reserve_and_recast_vote:", err) return } responsePayload, _ = json.Marshal(score) }) client.Subscribe(guid+".release", func(msg *yagnats.Message) { var inst instance.Instance responsePayload := errorResponse defer func() { client.Publish(msg.ReplyTo, responsePayload) }() err := json.Unmarshal(msg.Payload, &inst) if err != nil { log.Println(guid, "invalid reserve_and_recast_vote request:", err) return } rep.Release(inst) responsePayload = successResponse }) client.Subscribe(guid+".claim", func(msg *yagnats.Message) { var inst instance.Instance responsePayload := errorResponse defer func() { client.Publish(msg.ReplyTo, responsePayload) }() err := json.Unmarshal(msg.Payload, &inst) if err != nil { log.Println(guid, "invalid reserve_and_recast_vote request:", err) return } rep.Claim(inst) responsePayload = successResponse }) fmt.Printf("[%s] listening for nats\n", guid) select {} }