func internalPubAsync(clientTimer *time.Timer, msgBody *bytes.Buffer, topic *nsqd.Topic) error { if topic.Exiting() { return nsqd.ErrExiting } info := &nsqd.PubInfo{ Done: make(chan struct{}), MsgBody: msgBody, StartPub: time.Now(), } if clientTimer == nil { clientTimer = time.NewTimer(time.Second * 5) } else { clientTimer.Reset(time.Second * 5) } select { case topic.GetWaitChan() <- info: default: select { case topic.GetWaitChan() <- info: case <-topic.QuitChan(): nsqd.NsqLogger().Infof("topic %v put messages failed at exiting", topic.GetFullName()) return nsqd.ErrExiting case <-clientTimer.C: nsqd.NsqLogger().Infof("topic %v put messages timeout ", topic.GetFullName()) return ErrPubToWaitTimeout } } <-info.Done return info.Err }
func (c *context) internalPubLoop(topic *nsqd.Topic) { messages := make([]*nsqd.Message, 0, 100) pubInfoList := make([]*nsqd.PubInfo, 0, 100) topicName := topic.GetTopicName() partition := topic.GetTopicPart() nsqd.NsqLogger().Logf("start pub loop for topic: %v ", topic.GetFullName()) defer func() { done := false for !done { select { case info := <-topic.GetWaitChan(): pubInfoList = append(pubInfoList, info) default: done = true } } nsqd.NsqLogger().Logf("quit pub loop for topic: %v, left: %v ", topic.GetFullName(), len(pubInfoList)) for _, info := range pubInfoList { info.Err = nsqd.ErrExiting close(info.Done) } }() quitChan := topic.QuitChan() infoChan := topic.GetWaitChan() for { select { case <-quitChan: return case info := <-infoChan: if info.MsgBody.Len() <= 0 { nsqd.NsqLogger().Logf("empty msg body") } messages = append(messages, nsqd.NewMessage(0, info.MsgBody.Bytes())) pubInfoList = append(pubInfoList, info) // TODO: avoid too much in a batch default: if len(pubInfoList) == 0 { nsqd.NsqLogger().LogDebugf("topic %v pub loop waiting for message", topic.GetFullName()) select { case <-quitChan: return case info := <-infoChan: if info.MsgBody.Len() <= 0 { nsqd.NsqLogger().Logf("empty msg body") } messages = append(messages, nsqd.NewMessage(0, info.MsgBody.Bytes())) pubInfoList = append(pubInfoList, info) } continue } if len(pubInfoList) > 1 { nsqd.NsqLogger().LogDebugf("pub loop batch number: %v", len(pubInfoList)) } var retErr error if c.checkForMasterWrite(topicName, partition) { _, _, _, err := c.PutMessages(topic, messages) if err != nil { nsqd.NsqLogger().LogErrorf("topic %v put messages %v failed: %v", topic.GetFullName(), len(messages), err) retErr = err } } else { topic.DisableForSlave() nsqd.NsqLogger().LogDebugf("should put to master: %v", topic.GetFullName()) retErr = consistence.ErrNotTopicLeader.ToErrorType() } for _, info := range pubInfoList { info.Err = retErr close(info.Done) } pubInfoList = pubInfoList[:0] messages = messages[:0] } } }