func main() { snapshot, _ := zmq.NewSocket(zmq.DEALER) snapshot.Connect("tcp://localhost:5556") subscriber, _ := zmq.NewSocket(zmq.SUB) subscriber.SetRcvhwm(100000) // or messages between snapshot and next are lost subscriber.SetSubscribe("") subscriber.Connect("tcp://localhost:5557") time.Sleep(time.Second) // or messages between snapshot and next are lost kvmap := make(map[string]*kvsimple.Kvmsg) // Get state snapshot sequence := int64(0) snapshot.SendMessage("ICANHAZ?") for { kvmsg, err := kvsimple.RecvKvmsg(snapshot) if err != nil { fmt.Println(err) break // Interrupted } if key, _ := kvmsg.GetKey(); key == "KTHXBAI" { sequence, _ = kvmsg.GetSequence() fmt.Printf("Received snapshot=%d\n", sequence) break // Done } kvmsg.Store(kvmap) } snapshot.Close() first := true // Now apply pending updates, discard out-of-sequence messages for { kvmsg, err := kvsimple.RecvKvmsg(subscriber) if err != nil { fmt.Println(err) break // Interrupted } if seq, _ := kvmsg.GetSequence(); seq > sequence { sequence, _ = kvmsg.GetSequence() kvmsg.Store(kvmap) if first { // Show what the first regular update is after the snapshot, // to see if we missed updates. first = false fmt.Println("Next:", sequence) } } } }
func main() { snapshot, _ := zmq.NewSocket(zmq.ROUTER) snapshot.Bind("tcp://*:5556") publisher, _ := zmq.NewSocket(zmq.PUB) publisher.Bind("tcp://*:5557") collector, _ := zmq.NewSocket(zmq.PULL) collector.Bind("tcp://*:5558") // The body of the main task collects updates from clients and // publishes them back out to clients: sequence := int64(0) kvmap := make(map[string]*kvsimple.Kvmsg) poller := zmq.NewPoller() poller.Add(collector, zmq.POLLIN) poller.Add(snapshot, zmq.POLLIN) LOOP: for { polled, err := poller.Poll(1000 * time.Millisecond) if err != nil { break } for _, item := range polled { switch socket := item.Socket; socket { case collector: // Apply state update sent from client kvmsg, err := kvsimple.RecvKvmsg(collector) if err != nil { break LOOP // Interrupted } sequence++ kvmsg.SetSequence(sequence) kvmsg.Send(publisher) kvmsg.Store(kvmap) fmt.Println("I: publishing update", sequence) case snapshot: // Execute state snapshot request msg, err := snapshot.RecvMessage(0) if err != nil { break LOOP } identity := msg[0] // Request is in second frame of message request := msg[1] if request != "ICANHAZ?" { fmt.Println("E: bad request, aborting") break LOOP } // Send state snapshot to client // For each entry in kvmap, send kvmsg to client for _, kvmsg := range kvmap { snapshot.Send(identity, zmq.SNDMORE) kvmsg.Send(snapshot) } // Now send END message with sequence number fmt.Println("I: sending shapshot =", sequence) snapshot.Send(identity, zmq.SNDMORE) kvmsg := kvsimple.NewKvmsg(sequence) kvmsg.SetKey("KTHXBAI") kvmsg.SetBody("") kvmsg.Send(snapshot) } } } fmt.Printf("Interrupted\n%d messages handled\n", sequence) }
func main() { snapshot, _ := zmq.NewSocket(zmq.DEALER) snapshot.Connect("tcp://localhost:5556") subscriber, _ := zmq.NewSocket(zmq.SUB) subscriber.SetSubscribe(SUBTREE) subscriber.Connect("tcp://localhost:5557") publisher, _ := zmq.NewSocket(zmq.PUSH) publisher.Connect("tcp://localhost:5558") kvmap := make(map[string]*kvsimple.Kvmsg) rand.Seed(time.Now().UnixNano()) // We first request a state snapshot: sequence := int64(0) snapshot.SendMessage("ICANHAZ?", SUBTREE) for { kvmsg, err := kvsimple.RecvKvmsg(snapshot) if err != nil { break // Interrupted } if key, _ := kvmsg.GetKey(); key == "KTHXBAI" { sequence, _ := kvmsg.GetSequence() fmt.Println("I: received snapshot =", sequence) break // Done } kvmsg.Store(kvmap) } snapshot.Close() poller := zmq.NewPoller() poller.Add(subscriber, zmq.POLLIN) alarm := time.Now().Add(1000 * time.Millisecond) for { tickless := alarm.Sub(time.Now()) if tickless < 0 { tickless = 0 } polled, err := poller.Poll(tickless) if err != nil { break // Context has been shut down } if len(polled) == 1 { kvmsg, err := kvsimple.RecvKvmsg(subscriber) if err != nil { break // Interrupted } // Discard out-of-sequence kvmsgs, incl. heartbeats if seq, _ := kvmsg.GetSequence(); seq > sequence { sequence = seq kvmsg.Store(kvmap) fmt.Println("I: received update =", sequence) } } // If we timed-out, generate a random kvmsg if time.Now().After(alarm) { kvmsg := kvsimple.NewKvmsg(0) kvmsg.SetKey(fmt.Sprintf("%s%d", SUBTREE, rand.Intn(10000))) kvmsg.SetBody(fmt.Sprint(rand.Intn(1000000))) kvmsg.Send(publisher) alarm = time.Now().Add(1000 * time.Millisecond) } } fmt.Printf("Interrupted\n%d messages in\n", sequence) }
func state_manager() { kvmap := make(map[string]*kvsimple.Kvmsg) pipe, _ := zmq.NewSocket(zmq.PAIR) pipe.Connect("inproc://pipe") pipe.SendMessage("READY") snapshot, _ := zmq.NewSocket(zmq.ROUTER) snapshot.Bind("tcp://*:5556") poller := zmq.NewPoller() poller.Add(pipe, zmq.POLLIN) poller.Add(snapshot, zmq.POLLIN) sequence := int64(0) // Current snapshot version number LOOP: for { polled, err := poller.Poll(-1) if err != nil { break // Context has been shut down } for _, item := range polled { switch socket := item.Socket; socket { case pipe: // Apply state update from main thread kvmsg, err := kvsimple.RecvKvmsg(pipe) if err != nil { break LOOP // Interrupted } sequence, _ = kvmsg.GetSequence() kvmsg.Store(kvmap) case snapshot: // Execute state snapshot request msg, err := snapshot.RecvMessage(0) if err != nil { break LOOP // Interrupted } identity := msg[0] // Request is in second frame of message request := msg[1] if request != "ICANHAZ?" { fmt.Println("E: bad request, aborting") break LOOP } // Send state snapshot to client // For each entry in kvmap, send kvmsg to client for _, kvmsg := range kvmap { snapshot.Send(identity, zmq.SNDMORE) kvmsg.Send(snapshot) } // Give client some time to deal with it. // This reduces the risk that the client won't see // the END message, but it doesn't eliminate the risk. time.Sleep(100 * time.Millisecond) // Now send END message with sequence number fmt.Printf("Sending state shapshot=%d\n", sequence) snapshot.Send(identity, zmq.SNDMORE) kvmsg := kvsimple.NewKvmsg(sequence) kvmsg.SetKey("KTHXBAI") kvmsg.SetBody("") kvmsg.Send(snapshot) } } } }