You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
2.4 KiB
Go

package consumer
import (
"context"
"joybuywork/internal/app"
"errors"
"fmt"
"github.com/Shopify/sarama"
"github.com/rs/xid"
"gits.branchcn.com/backend/microcode/plugins/kafka"
"time"
)
const (
defaultConsumerNum = 5 //默认消费者数
)
type Receive func(session sarama.ConsumerGroupSession, message *sarama.ConsumerMessage)
type CParams struct {
Topic string
Num int
Name string
GroupName string
Config *sarama.Config
}
type IConsumer interface {
Receive(session sarama.ConsumerGroupSession, message *sarama.ConsumerMessage)
Params() CParams
}
type Consumer struct {
c IConsumer
cp CParams
}
func NewConsumer(consumer IConsumer) (*Consumer, error) {
c := &Consumer{
c: consumer,
cp: consumer.Params(),
}
if c.cp.Topic == "" {
return nil, errors.New("topic empty")
}
if c.cp.GroupName == "" {
return nil, errors.New("group_name empty")
}
if c.cp.Num == 0 {
c.cp.Num = defaultConsumerNum
}
if c.cp.Config == nil {
c.cp.Config = kafka.DefaultConsumerConfig()
}
if c.cp.Name == "" {
c.cp.Name = xid.New().String()
}
return c, nil
}
func (c *Consumer) Run() {
handler := newGroupHandler(c.c.Receive)
for i := 0; i < c.cp.Num; i++ {
idx := i
app.GoSafeRetry(func() {
start(handler, c.cp, idx)
}, func() {
app.Logger.Warn(context.Background(), "消费者将在5秒后尝试重新启动", "")
time.Sleep(5 * time.Second)
start(handler, c.cp, idx)
}, "消费者组", c.cp.GroupName)
}
return
}
// 启动一个消费任务
func start(handler *GroupHandler, conf CParams, idx int) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// 创建消费者组
consumerGroup, err := app.Kafka.NewConsumerGroup(conf.GroupName, conf.Config)
if err != nil {
app.Logger.Error(ctx, fmt.Sprintf("创建消费者组出错:%v", err))
return
}
defer consumerGroup.Close()
//加入全局运行任务
mark := fmt.Sprintf("%s-%d", conf.Name, idx)
RTS[mark] = &Task{
gh: handler,
cancel: cancel,
}
for {
if err = consumerGroup.Consume(ctx, []string{conf.Topic}, handler); err != nil {
app.Logger.Error(ctx, fmt.Sprintf("消费出错:%v", err))
}
if handler.Closed() {
// 消费者处理程序被关闭,退出消费循环
delete(RTS, mark)
break
}
app.Logger.Warn(ctx, fmt.Sprintf("消费者(%s-%d)重新分配", conf.Name, idx))
}
app.Logger.Warn(ctx, fmt.Sprintf("消费者(%s-%d)结束消费", conf.Name, idx))
}