这篇博客我们先来看一下消费者消费的流程,下面就是使用一个消费者的简单demo
// ConsumerHandler 消费者处理者
type ConsumerHandler struct{}
// HandleMessage 处理消息
func (*ConsumerHandler) HandleMessage(msg *nsq.Message) error {
fmt.Println(string(msg.Body))
return nil
}
//消费者
func Consumer() {
consumer, err := nsq.NewConsumer("test", "test-channel", nsq.NewConfig())
if err != nil {
fmt.Println("NewConsumer", err)
panic(err)
}
consumer.AddHandler(&ConsumerHandler{})
if err := consumer.ConnectToNSQLookupd("127.0.0.1:4161"); err != nil {
fmt.Println("ConnectToNSQLookupd", err)
panic(err)
}
}
在声明一个消费者的时候直接nsq的NewConsumer方法,第一个参数是topic,第二个参数是channel的名字,第三个参数是consumer的默认配置。创建好之后向consumer中添加我们自定义的一个handler,它是实现了Handler接口的HandleMessage。最后连接nsqlookupd,在之后的博客中我们会对他进行分析。
先来看一下NewConsumer创建consumer的过程:
func NewConsumer(topic string, channel string, config *Config) (*Consumer, error) {
config.assertInitialized()
if err := config.Validate(); err != nil {
return nil, err
}
if !IsValidTopicName(topic) {
return nil, errors.New("invalid topic name")
}
if !IsValidChannelName(channel) {
return nil, errors.New("invalid channel name")
}
r := &Consumer{
id: atomic.AddInt64(&instCount, 1),
topic: topic,
channel: channel,
config: *config,
logger: log.New(os.Stderr, "", log.Flags()),
logLvl: LogLevelInfo,
maxInFlight: int32(config.MaxInFlight),
incomingMessages: make(chan *Message),
rdyRetryTimers: make(map[string]*time.Timer),
pendingConnections: make(map[string]*Conn),
connections: make(map[string]*Conn),
lookupdRecheckChan: make(chan int, 1),
rng: rand.New(rand.NewSource(time.Now().UnixNano())),
StopChan: make(chan int),
exitChan: make(chan int),
}
r.wg.Add(1)
go r.rdyLoop()
return r, nil
}
首先对我们传入的参数进行验证,验证都通过之后初始化consumer里面字段的值,最后启动了一个goroutine用了定时更新RDY的值,它是用来控制服务端向客户端推送的消息的数量的。
func (r *Consumer) AddHandler(handler Handler) {
r.AddConcurrentHandlers(handler, 1)
}
在向consumer中添加handler的时候,又调用了另外的方法,看名字应该是并发执行handler的数量,在这里了默认传入的是1
func (r *Consumer) AddConcurrentHandlers(handler Handler, concurrency int) {
if atomic.LoadInt32(&r.connectedFlag) == 1 {
panic("already connected")
}
atomic.AddInt32(&r.runningHandlers, int32(concurrency))
for i := 0; i < concurrency; i++ {
go r.handlerLoop(handler)
}
}
concurrency 就是用来说明我们现在传入的handler要并发执行多少个,首先对正在运行的handler进行计数,然后根据并发量启动handler开始工作,启动的每一个handler也都是一个goroutine
func (r *Consumer) handlerLoop(handler Handler) {
r.log(LogLevelDebug, "starting Handler")
for {
message, ok := <-r.incomingMessages
if !ok {
goto exit
}
if r.shouldFailMessage(message, handler) {
message.Finish()
continue
}
err := handler.HandleMessage(message)
if err != nil {
r.log(LogLevelError, "Handler returned error (%s) for msg %s", err, message.ID)
if !message.IsAutoResponseDisabled() {
message.Requeue(-1)
}
continue
}
if !message.IsAutoResponseDisabled() {
message.Finish()
}
}
exit:
r.log(Lo