mirror of
				https://github.com/openimsdk/open-im-server.git
				synced 2025-10-31 08:29:33 +08:00 
			
		
		
		
	refactor: refactor message queue
This commit is contained in:
		
							parent
							
								
									e863299c1a
								
							
						
					
					
						commit
						cb0a1a20f1
					
				
							
								
								
									
										8
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| # Default ignored files | ||||
| /shelf/ | ||||
| /workspace.xml | ||||
| # Editor-based HTTP Client requests | ||||
| /httpRequests/ | ||||
| # Datasource local storage ignored files | ||||
| /dataSources/ | ||||
| /dataSources.local.xml | ||||
							
								
								
									
										9
									
								
								.idea/Open-IM-Server.iml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								.idea/Open-IM-Server.iml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <module type="WEB_MODULE" version="4"> | ||||
|   <component name="Go" enabled="true" /> | ||||
|   <component name="NewModuleRootManager"> | ||||
|     <content url="file://$MODULE_DIR$" /> | ||||
|     <orderEntry type="inheritedJdk" /> | ||||
|     <orderEntry type="sourceFolder" forTests="false" /> | ||||
|   </component> | ||||
| </module> | ||||
							
								
								
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ProjectModuleManager"> | ||||
|     <modules> | ||||
|       <module fileurl="file://$PROJECT_DIR$/.idea/Open-IM-Server.iml" filepath="$PROJECT_DIR$/.idea/Open-IM-Server.iml" /> | ||||
|     </modules> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										6
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="VcsDirectoryMappings"> | ||||
|     <mapping directory="$PROJECT_DIR$" vcs="Git" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										3
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.sum
									
									
									
									
									
								
							| @ -141,7 +141,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw | ||||
| github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||
| github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= | ||||
| github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= | ||||
| github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| @ -181,12 +180,10 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW | ||||
| github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | ||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||||
| github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= | ||||
| github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= | ||||
| github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||||
| github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= | ||||
| github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= | ||||
| github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||
| github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= | ||||
| github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||||
| github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||||
| github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||||
|  | ||||
| @ -1,16 +1,18 @@ | ||||
| package logic | ||||
| 
 | ||||
| import ( | ||||
| 	"Open_IM/pkg/common/mq" | ||||
| 	"context" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"Open_IM/pkg/common/config" | ||||
| 	"Open_IM/pkg/common/constant" | ||||
| 	kfk "Open_IM/pkg/common/kafka" | ||||
| 	"Open_IM/pkg/common/log" | ||||
| 	kfk "Open_IM/pkg/common/mq/kafka" | ||||
| 	"Open_IM/pkg/grpc-etcdv3/getcdv3" | ||||
| 	pbMsg "Open_IM/pkg/proto/chat" | ||||
| 	pbPush "Open_IM/pkg/proto/push" | ||||
| 	"Open_IM/pkg/utils" | ||||
| 	"context" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/Shopify/sarama" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| @ -19,27 +21,24 @@ import ( | ||||
| type fcb func(msg []byte, msgKey string) | ||||
| 
 | ||||
| type HistoryConsumerHandler struct { | ||||
| 	msgHandle            map[string]fcb | ||||
| 	historyConsumerGroup *kfk.MConsumerGroup | ||||
| 	historyConsumerGroup mq.Consumer | ||||
| } | ||||
| 
 | ||||
| func (mc *HistoryConsumerHandler) Init() { | ||||
| 	mc.msgHandle = make(map[string]fcb) | ||||
| 	mc.msgHandle[config.Config.Kafka.Ws2mschat.Topic] = mc.handleChatWs2Mongo | ||||
| 	mc.historyConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{KafkaVersion: sarama.V0_10_2_0, | ||||
| 		OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.Ws2mschat.Topic}, | ||||
| 		config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo) | ||||
| 
 | ||||
| 		OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMongo) | ||||
| 	mc.historyConsumerGroup.RegisterMessageHandler(config.Config.Kafka.Ws2mschat.Topic, mq.MessageHandleFunc(mc.handleChatWs2Mongo)) | ||||
| } | ||||
| 
 | ||||
| func (mc *HistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string) { | ||||
| func (mc *HistoryConsumerHandler) handleChatWs2Mongo(message *mq.Message) error { | ||||
| 	msg, msgKey := message.Value, string(message.Key) | ||||
| 	log.InfoByKv("chat come mongo!!!", "", "chat", string(msg)) | ||||
| 	time := utils.GetCurrentTimestampByNano() | ||||
| 	pbData := pbMsg.WSToMsgSvrChatMsg{} | ||||
| 	err := proto.Unmarshal(msg, &pbData) | ||||
| 	if err != nil { | ||||
| 		log.ErrorByKv("msg_transfer Unmarshal chat err", "", "chat", string(msg), "err", err.Error()) | ||||
| 		return | ||||
| 		return err | ||||
| 	} | ||||
| 	pbSaveData := pbMsg.MsgSvrToPushSvrChatMsg{} | ||||
| 	pbSaveData.SendID = pbData.SendID | ||||
| @ -68,14 +67,14 @@ func (mc *HistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string) | ||||
| 				err := saveUserChat(pbData.RecvID, &pbSaveData) | ||||
| 				if err != nil { | ||||
| 					log.NewError(pbSaveData.OperationID, "single data insert to mongo err", err.Error(), pbSaveData.String()) | ||||
| 					return | ||||
| 					return err | ||||
| 				} | ||||
| 
 | ||||
| 			} else if msgKey == pbSaveData.SendID { | ||||
| 				err := saveUserChat(pbData.SendID, &pbSaveData) | ||||
| 				if err != nil { | ||||
| 					log.NewError(pbSaveData.OperationID, "single data insert to mongo err", err.Error(), pbSaveData.String()) | ||||
| 					return | ||||
| 					return err | ||||
| 				} | ||||
| 
 | ||||
| 			} | ||||
| @ -96,7 +95,7 @@ func (mc *HistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string) | ||||
| 			err := saveUserChat(uidAndGroupID[0], &pbSaveData) | ||||
| 			if err != nil { | ||||
| 				log.NewError(pbSaveData.OperationID, "group data insert to mongo err", pbSaveData.String(), uidAndGroupID[0], err.Error()) | ||||
| 				return | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		pbSaveData.Options = pbData.Options | ||||
| @ -104,22 +103,13 @@ func (mc *HistoryConsumerHandler) handleChatWs2Mongo(msg []byte, msgKey string) | ||||
| 		go sendMessageToPush(&pbSaveData) | ||||
| 	default: | ||||
| 		log.NewError(pbSaveData.OperationID, "SessionType error", pbSaveData.String()) | ||||
| 		return | ||||
| 		return nil // not retry | ||||
| 	} | ||||
| 	log.NewDebug(pbSaveData.OperationID, "msg_transfer handle topic data to database success...", pbSaveData.String()) | ||||
| } | ||||
| 
 | ||||
| func (HistoryConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error   { return nil } | ||||
| func (HistoryConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil } | ||||
| func (mc *HistoryConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, | ||||
| 	claim sarama.ConsumerGroupClaim) error { | ||||
| 	for msg := range claim.Messages() { | ||||
| 		log.InfoByKv("kafka get info to mongo", "", "msgTopic", msg.Topic, "msgPartition", msg.Partition, "chat", string(msg.Value)) | ||||
| 		mc.msgHandle[msg.Topic](msg.Value, string(msg.Key)) | ||||
| 		sess.MarkMessage(msg, "") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func sendMessageToPush(message *pbMsg.MsgSvrToPushSvrChatMsg) { | ||||
| 	log.InfoByKv("msg_transfer send message to push", message.OperationID, "message", message.String()) | ||||
| 	msg := pbPush.PushMsgReq{} | ||||
|  | ||||
| @ -2,14 +2,15 @@ package logic | ||||
| 
 | ||||
| import ( | ||||
| 	"Open_IM/pkg/common/config" | ||||
| 	"Open_IM/pkg/common/kafka" | ||||
| 	"Open_IM/pkg/common/log" | ||||
| 	"Open_IM/pkg/common/mq" | ||||
| 	"Open_IM/pkg/common/mq/kafka" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	persistentCH PersistentConsumerHandler | ||||
| 	historyCH    HistoryConsumerHandler | ||||
| 	producer     *kafka.Producer | ||||
| 	producer     mq.Producer | ||||
| ) | ||||
| 
 | ||||
| func Init() { | ||||
| @ -18,8 +19,9 @@ func Init() { | ||||
| 	historyCH.Init() | ||||
| 	producer = kafka.NewKafkaProducer(config.Config.Kafka.Ms2pschat.Addr, config.Config.Kafka.Ms2pschat.Topic) | ||||
| } | ||||
| 
 | ||||
| func Run() { | ||||
| 	//register mysqlConsumerHandler to | ||||
| 	go persistentCH.persistentConsumerGroup.RegisterHandleAndConsumer(&persistentCH) | ||||
| 	go historyCH.historyConsumerGroup.RegisterHandleAndConsumer(&historyCH) | ||||
| 	go persistentCH.persistentConsumerGroup.Start() | ||||
| 	go historyCH.historyConsumerGroup.Start() | ||||
| } | ||||
|  | ||||
| @ -7,38 +7,41 @@ | ||||
| package logic | ||||
| 
 | ||||
| import ( | ||||
| 	"Open_IM/pkg/common/mq" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"Open_IM/pkg/common/config" | ||||
| 	"Open_IM/pkg/common/constant" | ||||
| 	"Open_IM/pkg/common/db/mysql_model/im_mysql_msg_model" | ||||
| 	kfk "Open_IM/pkg/common/kafka" | ||||
| 	"Open_IM/pkg/common/log" | ||||
| 	kfk "Open_IM/pkg/common/mq/kafka" | ||||
| 	pbMsg "Open_IM/pkg/proto/chat" | ||||
| 	"Open_IM/pkg/utils" | ||||
| 
 | ||||
| 	"github.com/Shopify/sarama" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| type PersistentConsumerHandler struct { | ||||
| 	msgHandle               map[string]fcb | ||||
| 	persistentConsumerGroup *kfk.MConsumerGroup | ||||
| 	persistentConsumerGroup mq.Consumer | ||||
| } | ||||
| 
 | ||||
| func (pc *PersistentConsumerHandler) Init() { | ||||
| 	pc.msgHandle = make(map[string]fcb) | ||||
| 	pc.msgHandle[config.Config.Kafka.Ws2mschat.Topic] = pc.handleChatWs2Mysql | ||||
| 	pc.persistentConsumerGroup = kfk.NewMConsumerGroup(&kfk.MConsumerGroupConfig{KafkaVersion: sarama.V0_10_2_0, | ||||
| 		OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, []string{config.Config.Kafka.Ws2mschat.Topic}, | ||||
| 		OffsetsInitial: sarama.OffsetNewest, IsReturnErr: false}, | ||||
| 		config.Config.Kafka.Ws2mschat.Addr, config.Config.Kafka.ConsumerGroupID.MsgToMySql) | ||||
| 
 | ||||
| 	pc.persistentConsumerGroup.RegisterMessageHandler(config.Config.Kafka.Ws2mschat.Topic, mq.MessageHandleFunc(pc.handleChatWs2Mysql)) | ||||
| } | ||||
| func (pc *PersistentConsumerHandler) handleChatWs2Mysql(msg []byte, msgKey string) { | ||||
| 
 | ||||
| func (pc *PersistentConsumerHandler) handleChatWs2Mysql(message *mq.Message) error { | ||||
| 	msg, msgKey := message.Value, string(message.Key) | ||||
| 	log.InfoByKv("chat come here mysql!!!", "", "chat", string(msg)) | ||||
| 	pbData := pbMsg.WSToMsgSvrChatMsg{} | ||||
| 	err := proto.Unmarshal(msg, &pbData) | ||||
| 	if err != nil { | ||||
| 		log.ErrorByKv("msg_transfer Unmarshal chat err", "", "chat", string(msg), "err", err.Error()) | ||||
| 		return | ||||
| 		return nil // not retry | ||||
| 	} | ||||
| 	Options := utils.JsonStringToMap(pbData.Options) | ||||
| 	//Control whether to store history messages (mysql) | ||||
| @ -49,27 +52,18 @@ func (pc *PersistentConsumerHandler) handleChatWs2Mysql(msg []byte, msgKey strin | ||||
| 			log.InfoByKv("msg_transfer chat persisting", pbData.OperationID) | ||||
| 			if err = im_mysql_msg_model.InsertMessageToChatLog(pbData); err != nil { | ||||
| 				log.ErrorByKv("Message insert failed", pbData.OperationID, "err", err.Error(), "chat", pbData.String()) | ||||
| 				return | ||||
| 				return err | ||||
| 			} | ||||
| 		} else if pbData.SessionType == constant.GroupChatType && msgKey == "0" { | ||||
| 			pbData.RecvID = strings.Split(pbData.RecvID, " ")[1] | ||||
| 			log.InfoByKv("msg_transfer chat persisting", pbData.OperationID) | ||||
| 			if err = im_mysql_msg_model.InsertMessageToChatLog(pbData); err != nil { | ||||
| 				log.ErrorByKv("Message insert failed", pbData.OperationID, "err", err.Error(), "chat", pbData.String()) | ||||
| 				return | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
| func (PersistentConsumerHandler) Setup(_ sarama.ConsumerGroupSession) error   { return nil } | ||||
| func (PersistentConsumerHandler) Cleanup(_ sarama.ConsumerGroupSession) error { return nil } | ||||
| func (pc *PersistentConsumerHandler) ConsumeClaim(sess sarama.ConsumerGroupSession, | ||||
| 	claim sarama.ConsumerGroupClaim) error { | ||||
| 	for msg := range claim.Messages() { | ||||
| 		log.InfoByKv("kafka get info to mysql", "", "msgTopic", msg.Topic, "msgPartition", msg.Partition, "chat", string(msg.Value)) | ||||
| 		pc.msgHandle[msg.Topic](msg.Value, string(msg.Key)) | ||||
| 		sess.MarkMessage(msg, "") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @ -1,53 +0,0 @@ | ||||
| /* | ||||
| ** description(""). | ||||
| ** copyright('tuoyun,www.tuoyun.net'). | ||||
| ** author("fg,Gordon@tuoyun.net"). | ||||
| ** time(2021/5/11 9:36). | ||||
|  */ | ||||
| package kafka | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/Shopify/sarama" | ||||
| ) | ||||
| 
 | ||||
| type MConsumerGroup struct { | ||||
| 	sarama.ConsumerGroup | ||||
| 	groupID string | ||||
| 	topics  []string | ||||
| } | ||||
| 
 | ||||
| type MConsumerGroupConfig struct { | ||||
| 	KafkaVersion   sarama.KafkaVersion | ||||
| 	OffsetsInitial int64 | ||||
| 	IsReturnErr    bool | ||||
| } | ||||
| 
 | ||||
| func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addr []string, groupID string) *MConsumerGroup { | ||||
| 	config := sarama.NewConfig() | ||||
| 	config.Version = consumerConfig.KafkaVersion | ||||
| 	config.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial | ||||
| 	config.Consumer.Return.Errors = consumerConfig.IsReturnErr | ||||
| 	client, err := sarama.NewClient(addr, config) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	consumerGroup, err := sarama.NewConsumerGroupFromClient(groupID, client) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return &MConsumerGroup{ | ||||
| 		consumerGroup, | ||||
| 		groupID, | ||||
| 		topics, | ||||
| 	} | ||||
| } | ||||
| func (mc *MConsumerGroup) RegisterHandleAndConsumer(handler sarama.ConsumerGroupHandler) { | ||||
| 	ctx := context.Background() | ||||
| 	for { | ||||
| 		err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler) | ||||
| 		if err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										40
									
								
								pkg/common/mq/consumer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								pkg/common/mq/consumer.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| package mq | ||||
| 
 | ||||
| import "time" | ||||
| 
 | ||||
| type Consumer interface { | ||||
| 	// RegisterMessageHandler is used to register message handler | ||||
| 	// any received messages will be passed to handler to process | ||||
| 	// once the Consumer started, it is forbidden to register handlers. | ||||
| 	RegisterMessageHandler(topic string, handler MessageHandler) | ||||
| 
 | ||||
| 	// Start to consume messages | ||||
| 	Start() error | ||||
| } | ||||
| 
 | ||||
| type MessageHandler interface { | ||||
| 	// HandleMessage process received messages, | ||||
| 	// if returned error is nil, the message will be auto committed. | ||||
| 	HandleMessage(msg *Message) error | ||||
| } | ||||
| 
 | ||||
| type MessageHandleFunc func(msg *Message) error | ||||
| 
 | ||||
| func (fn MessageHandleFunc) HandleMessage(msg *Message) error { | ||||
| 	return fn(msg) | ||||
| } | ||||
| 
 | ||||
| type Message struct { | ||||
| 	Key, Value     []byte | ||||
| 	Topic          string | ||||
| 	Partition      int32 | ||||
| 	Offset         int64 | ||||
| 	Timestamp      time.Time       // only set if kafka is version 0.10+, inner message timestamp | ||||
| 	BlockTimestamp time.Time       // only set if kafka is version 0.10+, outer (compressed) block timestamp | ||||
| 	Headers        []*RecordHeader // only set if kafka is version 0.11+ | ||||
| } | ||||
| 
 | ||||
| type RecordHeader struct { | ||||
| 	Key   []byte | ||||
| 	Value []byte | ||||
| } | ||||
| @ -33,4 +33,5 @@ func NewKafkaConsumer(addr []string, topic string) *Consumer { | ||||
| 	p.PartitionList = partitionList | ||||
| 
 | ||||
| 	return &p | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										110
									
								
								pkg/common/mq/kafka/consumer_group.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								pkg/common/mq/kafka/consumer_group.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,110 @@ | ||||
| /* | ||||
| ** description(""). | ||||
| ** copyright('tuoyun,www.tuoyun.net'). | ||||
| ** author("fg,Gordon@tuoyun.net"). | ||||
| ** time(2021/5/11 9:36). | ||||
|  */ | ||||
| package kafka | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"Open_IM/pkg/common/mq" | ||||
| 
 | ||||
| 	"github.com/Shopify/sarama" | ||||
| ) | ||||
| 
 | ||||
| type kafkaConsumerGroup struct { | ||||
| 	sarama.ConsumerGroup | ||||
| 	groupID string | ||||
| 
 | ||||
| 	mu       *sync.RWMutex | ||||
| 	handlers map[string][]mq.MessageHandler | ||||
| } | ||||
| 
 | ||||
| var _ mq.Consumer = (*kafkaConsumerGroup)(nil) | ||||
| 
 | ||||
| type MConsumerGroupConfig struct { | ||||
| 	KafkaVersion   sarama.KafkaVersion | ||||
| 	OffsetsInitial int64 | ||||
| 	IsReturnErr    bool | ||||
| } | ||||
| 
 | ||||
| func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, addr []string, groupID string) *kafkaConsumerGroup { | ||||
| 	config := sarama.NewConfig() | ||||
| 	config.Version = consumerConfig.KafkaVersion | ||||
| 	config.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial | ||||
| 	config.Consumer.Return.Errors = consumerConfig.IsReturnErr | ||||
| 	client, err := sarama.NewClient(addr, config) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	consumerGroup, err := sarama.NewConsumerGroupFromClient(groupID, client) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return &kafkaConsumerGroup{ | ||||
| 		ConsumerGroup: consumerGroup, | ||||
| 		groupID:       groupID, | ||||
| 		handlers:      make(map[string][]mq.MessageHandler), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (mc *kafkaConsumerGroup) RegisterMessageHandler(topic string, handler mq.MessageHandler) { | ||||
| 	mc.mu.Lock() | ||||
| 	defer mc.mu.Unlock() | ||||
| 
 | ||||
| 	handlers := mc.handlers[topic] | ||||
| 	handlers = append(handlers, handler) | ||||
| 	mc.handlers[topic] = handlers | ||||
| } | ||||
| 
 | ||||
| func (mc *kafkaConsumerGroup) Start() error { | ||||
| 	topics := make([]string, 0, len(mc.handlers)) | ||||
| 	for topic := range mc.handlers { | ||||
| 		topics = append(topics, topic) | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := context.Background() | ||||
| 	for { | ||||
| 		err := mc.ConsumerGroup.Consume(ctx, topics, mc) | ||||
| 		if err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (mc *kafkaConsumerGroup) Setup(sarama.ConsumerGroupSession) error   { return nil } | ||||
| func (mc *kafkaConsumerGroup) Cleanup(sarama.ConsumerGroupSession) error { return nil } | ||||
| func (mc *kafkaConsumerGroup) ConsumeClaim(sess sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error { | ||||
| 	for msg := range claim.Messages() { | ||||
| 
 | ||||
| 		mc.mu.RLock() | ||||
| 		handlers, ok := mc.handlers[msg.Topic] | ||||
| 		mc.mu.RUnlock() | ||||
| 		if !ok { | ||||
| 			panic(fmt.Sprintf("no handlers for topic: %s", msg.Topic)) | ||||
| 		} | ||||
| 
 | ||||
| 		message := &mq.Message{ | ||||
| 			Key:       msg.Key, | ||||
| 			Value:     msg.Value, | ||||
| 			Topic:     msg.Topic, | ||||
| 			Partition: msg.Partition, | ||||
| 			Offset:    msg.Offset, | ||||
| 			Timestamp: msg.Timestamp, | ||||
| 		} | ||||
| 		for _, handler := range handlers { | ||||
| 			for { | ||||
| 				if err := handler.HandleMessage(message); err == nil { // error is nil, auto commit | ||||
| 					sess.MarkMessage(msg, "") | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| @ -2,19 +2,22 @@ package kafka | ||||
| 
 | ||||
| import ( | ||||
| 	log2 "Open_IM/pkg/common/log" | ||||
| 	"Open_IM/pkg/common/mq" | ||||
| 	"github.com/Shopify/sarama" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| ) | ||||
| 
 | ||||
| type Producer struct { | ||||
| type kafkaProducer struct { | ||||
| 	topic    string | ||||
| 	addr     []string | ||||
| 	config   *sarama.Config | ||||
| 	producer sarama.SyncProducer | ||||
| } | ||||
| 
 | ||||
| func NewKafkaProducer(addr []string, topic string) *Producer { | ||||
| 	p := Producer{} | ||||
| var _ mq.Producer = (*kafkaProducer)(nil) | ||||
| 
 | ||||
| func NewKafkaProducer(addr []string, topic string) *kafkaProducer { | ||||
| 	p := kafkaProducer{} | ||||
| 	p.config = sarama.NewConfig()                             //Instantiate a sarama Config | ||||
| 	p.config.Producer.Return.Successes = true                 //Whether to enable the successes channel to be notified after the message is sent successfully | ||||
| 	p.config.Producer.RequiredAcks = sarama.WaitForAll        //Set producer Message Reply level 0 1 all | ||||
| @ -32,7 +35,7 @@ func NewKafkaProducer(addr []string, topic string) *Producer { | ||||
| 	return &p | ||||
| } | ||||
| 
 | ||||
| func (p *Producer) SendMessage(m proto.Message, key ...string) (int32, int64, error) { | ||||
| func (p *kafkaProducer) SendMessage(m proto.Message, key ...string) (int32, int64, error) { | ||||
| 	kMsg := &sarama.ProducerMessage{} | ||||
| 	kMsg.Topic = p.topic | ||||
| 	if len(key) == 1 { | ||||
							
								
								
									
										7
									
								
								pkg/common/mq/producer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								pkg/common/mq/producer.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| package mq | ||||
| 
 | ||||
| import "github.com/golang/protobuf/proto" | ||||
| 
 | ||||
| type Producer interface { | ||||
| 	SendMessage(m proto.Message, key ...string) (int32, int64, error) | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user