func sendMessageAndExpectAnAck(stream *comm.Stream, dead chan bool, message *messages.Message) { err := stream.WriteMessage(message) if err != nil { log.Printf("Unable to send message to client: %v\n", err) dead <- true return } expectedAck := messages.MessageAck{ Partition: message.Partition, Offset: message.Offset, } acks[expectedAck] = make(chan bool) go func() { select { case _ = <-acks[expectedAck]: break case <-time.After(50 * time.Millisecond): if !message.IsAckRequest { blackHole.inbox <- *message } dead <- true } delete(acks, expectedAck) }() }
func handleClient(stream *comm.Stream) { defer stream.Close() var instanceId string instanceId, err := stream.ReadLine() if err != nil { log.Printf("Unable to identify client: %v\n", err) return } if instanceId == "-PING\n" { log.V(1).Printf("got ping: -PING; answering with: +PONG\n") err = stream.WriteLine("+PONG") if err != nil { log.Printf("Unable to answer with +PONG: %v\n", err) } return } log.V(1).Printf("got client: %s\n", instanceId) inbox := make(chan messages.Message, CHANNEL_BUFFER_SIZE) client := clientInbox{ inbox: inbox, count: 1, } addClient(instanceId, client) ackErrors := make(chan error) go func() { for { var ack messages.MessageAck err = stream.ReadMessage(&ack) if err != nil { ackErrors <- err continue } if _, found := acks[ack]; found { log.V(2).Printf("Got ack: %v\n", ack) acks[ack] <- true } } }() dead := make(chan bool) for { select { case message := <-inbox: go sendMessageAndExpectAnAck(stream, dead, &message) case <-time.Tick(75 * time.Millisecond): go sendMessageAndExpectAnAck(stream, dead, ackRequest) case err := <-ackErrors: log.V(3).Printf("Got ack error: %v\n", err) case <-dead: log.V(2).Printf("Client %v disconnected\n", instanceId) clientDead(instanceId) } } }