diff options
Diffstat (limited to 'weed/mq/client')
| -rw-r--r-- | weed/mq/client/cmd/weed_pub/publisher.go | 11 | ||||
| -rw-r--r-- | weed/mq/client/cmd/weed_sub/subscriber.go | 30 | ||||
| -rw-r--r-- | weed/mq/client/pub_client/connect.go | 11 | ||||
| -rw-r--r-- | weed/mq/client/pub_client/lookup.go | 4 | ||||
| -rw-r--r-- | weed/mq/client/pub_client/publish.go | 6 | ||||
| -rw-r--r-- | weed/mq/client/pub_client/publisher.go | 2 | ||||
| -rw-r--r-- | weed/mq/client/sub_client/connect_to_sub_coordinator.go | 171 | ||||
| -rw-r--r-- | weed/mq/client/sub_client/lookup.go | 34 | ||||
| -rw-r--r-- | weed/mq/client/sub_client/process.go | 85 | ||||
| -rw-r--r-- | weed/mq/client/sub_client/subscribe.go | 41 | ||||
| -rw-r--r-- | weed/mq/client/sub_client/subscriber.go | 18 |
11 files changed, 227 insertions, 186 deletions
diff --git a/weed/mq/client/cmd/weed_pub/publisher.go b/weed/mq/client/cmd/weed_pub/publisher.go index ee00be9f8..59469e66b 100644 --- a/weed/mq/client/cmd/weed_pub/publisher.go +++ b/weed/mq/client/cmd/weed_pub/publisher.go @@ -12,7 +12,8 @@ import ( var ( messageCount = flag.Int("n", 1000, "message count") - concurrency = flag.Int("c", 4, "concurrency count") + concurrency = flag.Int("c", 4, "concurrent publishers") + partitionCount = flag.Int("p", 6, "partition count") namespace = flag.String("ns", "test", "namespace") topic = flag.String("topic", "test", "topic") @@ -25,7 +26,10 @@ func doPublish(publisher *pub_client.TopicPublisher, id int) { // Simulate publishing a message key := []byte(fmt.Sprintf("key-%d-%d", id, i)) value := []byte(fmt.Sprintf("value-%d-%d", id, i)) - publisher.Publish(key, value) // Call your publisher function here + if err := publisher.Publish(key, value); err != nil { + fmt.Println(err) + break + } // println("Published", string(key), string(value)) } elapsed := time.Since(startTime) @@ -35,7 +39,8 @@ func doPublish(publisher *pub_client.TopicPublisher, id int) { func main() { flag.Parse() config := &pub_client.PublisherConfiguration{ - CreateTopic: true, + CreateTopic: true, + CreateTopicPartitionCount: int32(*partitionCount), } publisher := pub_client.NewTopicPublisher(*namespace, *topic, config) brokers := strings.Split(*seedBrokers, ",") diff --git a/weed/mq/client/cmd/weed_sub/subscriber.go b/weed/mq/client/cmd/weed_sub/subscriber.go index d5bd8f12d..a175c948a 100644 --- a/weed/mq/client/cmd/weed_sub/subscriber.go +++ b/weed/mq/client/cmd/weed_sub/subscriber.go @@ -3,7 +3,9 @@ package main import ( "flag" "fmt" + "github.com/seaweedfs/seaweedfs/weed/glog" "github.com/seaweedfs/seaweedfs/weed/mq/client/sub_client" + "github.com/seaweedfs/seaweedfs/weed/util" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "strings" @@ -14,35 +16,43 @@ var ( namespace = flag.String("ns", "test", "namespace") topic = flag.String("topic", "test", "topic") seedBrokers = flag.String("brokers", "localhost:17777", "seed brokers") + + clientId = flag.Uint("client_id", uint(util.RandomInt32()), "client id") ) func main() { flag.Parse() subscriberConfig := &sub_client.SubscriberConfiguration{ - ClientId: "testSubscriber", - GroupId: "test", - GroupInstanceId: "test", - GrpcDialOption: grpc.WithTransportCredentials(insecure.NewCredentials()), + ClientId: fmt.Sprintf("client-%d", *clientId), + ConsumerGroup: "test", + ConsumerGroupInstanceId: fmt.Sprintf("client-%d", *clientId), + GrpcDialOption: grpc.WithTransportCredentials(insecure.NewCredentials()), } contentConfig := &sub_client.ContentConfiguration{ Namespace: *namespace, Topic: *topic, Filter: "", - StartTime: time.Now(), + StartTime: time.Unix(1, 1), + } + + processorConfig := sub_client.ProcessorConfiguration{ + ConcurrentPartitionLimit: 3, } brokers := strings.Split(*seedBrokers, ",") - subscriber := sub_client.NewTopicSubscriber(brokers, subscriberConfig, contentConfig) + subscriber := sub_client.NewTopicSubscriber(brokers, subscriberConfig, contentConfig, processorConfig) - subscriber.SetEachMessageFunc(func(key, value []byte) bool { - println(string(key), "=>", string(value)) - return true + counter := 0 + subscriber.SetEachMessageFunc(func(key, value []byte) (bool, error) { + counter++ + println(string(key), "=>", string(value), counter) + return true, nil }) subscriber.SetCompletionFunc(func() { - println("done subscribing") + glog.V(0).Infof("done recived %d messages", counter) }) if err := subscriber.Subscribe(); err != nil { diff --git a/weed/mq/client/pub_client/connect.go b/weed/mq/client/pub_client/connect.go index fc7ff4d77..7f6d62a67 100644 --- a/weed/mq/client/pub_client/connect.go +++ b/weed/mq/client/pub_client/connect.go @@ -21,17 +21,17 @@ func (p *TopicPublisher) doConnect(partition *mq_pb.Partition, brokerAddress str return publishClient, fmt.Errorf("dial broker %s: %v", brokerAddress, err) } brokerClient := mq_pb.NewSeaweedMessagingClient(grpcConnection) - stream, err := brokerClient.Publish(context.Background()) + stream, err := brokerClient.PublishMessage(context.Background()) if err != nil { return publishClient, fmt.Errorf("create publish client: %v", err) } publishClient = &PublishClient{ - SeaweedMessaging_PublishClient: stream, + SeaweedMessaging_PublishMessageClient: stream, Broker: brokerAddress, } - if err = publishClient.Send(&mq_pb.PublishRequest{ - Message: &mq_pb.PublishRequest_Init{ - Init: &mq_pb.PublishRequest_InitMessage{ + if err = publishClient.Send(&mq_pb.PublishMessageRequest{ + Message: &mq_pb.PublishMessageRequest_Init{ + Init: &mq_pb.PublishMessageRequest_InitMessage{ Topic: &mq_pb.Topic{ Namespace: p.namespace, Name: p.topic, @@ -40,6 +40,7 @@ func (p *TopicPublisher) doConnect(partition *mq_pb.Partition, brokerAddress str RingSize: partition.RingSize, RangeStart: partition.RangeStart, RangeStop: partition.RangeStop, + UnixTimeNs: partition.UnixTimeNs, }, AckInterval: 128, }, diff --git a/weed/mq/client/pub_client/lookup.go b/weed/mq/client/pub_client/lookup.go index e55bfd256..ccc83b58d 100644 --- a/weed/mq/client/pub_client/lookup.go +++ b/weed/mq/client/pub_client/lookup.go @@ -3,6 +3,7 @@ package pub_client import ( "context" "fmt" + "github.com/seaweedfs/seaweedfs/weed/glog" "github.com/seaweedfs/seaweedfs/weed/pb" "github.com/seaweedfs/seaweedfs/weed/pb/mq_pb" ) @@ -39,6 +40,7 @@ func (p *TopicPublisher) doLookupAndConnect(brokerAddress string) error { }, IsForPublish: true, }) + glog.V(0).Infof("lookup1 topic %s/%s: %v", p.namespace, p.topic, lookupResp) if p.config.CreateTopic && err != nil { _, err = client.ConfigureTopic(context.Background(), &mq_pb.ConfigureTopicRequest{ Topic: &mq_pb.Topic{ @@ -58,12 +60,14 @@ func (p *TopicPublisher) doLookupAndConnect(brokerAddress string) error { }, IsForPublish: true, }) + glog.V(0).Infof("lookup2 topic %s/%s: %v", p.namespace, p.topic, lookupResp) } if err != nil { return err } for _, brokerPartitionAssignment := range lookupResp.BrokerPartitionAssignments { + glog.V(0).Infof("topic %s/%s partition %v leader %s followers %v", p.namespace, p.topic, brokerPartitionAssignment.Partition, brokerPartitionAssignment.LeaderBroker, brokerPartitionAssignment.FollowerBrokers) // partition => publishClient publishClient, err := p.doConnect(brokerPartitionAssignment.Partition, brokerPartitionAssignment.LeaderBroker) if err != nil { diff --git a/weed/mq/client/pub_client/publish.go b/weed/mq/client/pub_client/publish.go index 1e250ede3..4b0dfade9 100644 --- a/weed/mq/client/pub_client/publish.go +++ b/weed/mq/client/pub_client/publish.go @@ -12,7 +12,7 @@ func (p *TopicPublisher) Publish(key, value []byte) error { if hashKey < 0 { hashKey = -hashKey } - publishClient, found := p.partition2Broker.Floor(hashKey, hashKey) + publishClient, found := p.partition2Broker.Floor(hashKey+1, hashKey+1) if !found { return fmt.Errorf("no broker found for key %d", hashKey) } @@ -27,8 +27,8 @@ func (p *TopicPublisher) Publish(key, value []byte) error { //google.golang.org/grpc.(*clientStream).SendMsg(stream.go:894) //github.com/seaweedfs/seaweedfs/weed/pb/mq_pb.(*seaweedMessagingPublishClient).Send(mq_grpc.pb.go:141) //github.com/seaweedfs/seaweedfs/weed/mq/client/pub_client.(*TopicPublisher).Publish(publish.go:19) - if err := publishClient.Send(&mq_pb.PublishRequest{ - Message: &mq_pb.PublishRequest_Data{ + if err := publishClient.Send(&mq_pb.PublishMessageRequest{ + Message: &mq_pb.PublishMessageRequest_Data{ Data: &mq_pb.DataMessage{ Key: key, Value: value, diff --git a/weed/mq/client/pub_client/publisher.go b/weed/mq/client/pub_client/publisher.go index a0c26db36..d5176f21b 100644 --- a/weed/mq/client/pub_client/publisher.go +++ b/weed/mq/client/pub_client/publisher.go @@ -17,7 +17,7 @@ type PublisherConfiguration struct { } type PublishClient struct { - mq_pb.SeaweedMessaging_PublishClient + mq_pb.SeaweedMessaging_PublishMessageClient Broker string Err error } diff --git a/weed/mq/client/sub_client/connect_to_sub_coordinator.go b/weed/mq/client/sub_client/connect_to_sub_coordinator.go new file mode 100644 index 000000000..6d0eb0d43 --- /dev/null +++ b/weed/mq/client/sub_client/connect_to_sub_coordinator.go @@ -0,0 +1,171 @@ +package sub_client + +import ( + "context" + "fmt" + "github.com/seaweedfs/seaweedfs/weed/glog" + "github.com/seaweedfs/seaweedfs/weed/pb" + "github.com/seaweedfs/seaweedfs/weed/pb/mq_pb" + "io" + "sync" + "time" +) + +func (sub *TopicSubscriber) doKeepConnectedToSubCoordinator() { + waitTime := 1 * time.Second + for { + for _, broker := range sub.bootstrapBrokers { + // TODO find the balancer + // connect to the balancer + pb.WithBrokerGrpcClient(true, broker, sub.SubscriberConfig.GrpcDialOption, func(client mq_pb.SeaweedMessagingClient) error { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + stream, err := client.SubscriberToSubCoordinator(ctx) + if err != nil { + glog.V(0).Infof("subscriber %s/%s: %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, err) + return err + } + waitTime = 1 * time.Second + + // Maybe later: subscribe to multiple topics instead of just one + + if err := stream.Send(&mq_pb.SubscriberToSubCoordinatorRequest{ + Message: &mq_pb.SubscriberToSubCoordinatorRequest_Init{ + Init: &mq_pb.SubscriberToSubCoordinatorRequest_InitMessage{ + ConsumerGroup: sub.SubscriberConfig.ConsumerGroup, + ConsumerGroupInstanceId: sub.SubscriberConfig.ConsumerGroupInstanceId, + Topic: &mq_pb.Topic{ + Namespace: sub.ContentConfig.Namespace, + Name: sub.ContentConfig.Topic, + }, + }, + }, + }); err != nil { + glog.V(0).Infof("subscriber %s/%s send init: %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, err) + return err + } + + // keep receiving messages from the sub coordinator + for { + resp, err := stream.Recv() + if err != nil { + glog.V(0).Infof("subscriber %s/%s receive: %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, err) + return err + } + assignment := resp.GetAssignment() + if assignment != nil { + glog.V(0).Infof("subscriber %s/%s receive assignment: %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, assignment) + } + sub.onEachAssignment(assignment) + } + + return nil + }) + } + glog.V(0).Infof("subscriber %s/%s/%s waiting for more assignments", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, sub.SubscriberConfig.ConsumerGroup) + if waitTime < 10*time.Second { + waitTime += 1 * time.Second + } + time.Sleep(waitTime) + } +} + +func (sub *TopicSubscriber) onEachAssignment(assignment *mq_pb.SubscriberToSubCoordinatorResponse_Assignment) { + if assignment == nil { + return + } + // process each partition, with a concurrency limit + var wg sync.WaitGroup + semaphore := make(chan struct{}, sub.ProcessorConfig.ConcurrentPartitionLimit) + + for _, assigned := range assignment.AssignedPartitions { + wg.Add(1) + semaphore <- struct{}{} + go func(partition *mq_pb.Partition, broker string) { + defer wg.Done() + defer func() { <-semaphore }() + glog.V(0).Infof("subscriber %s/%s/%s assigned partition %+v at %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, sub.SubscriberConfig.ConsumerGroup, partition, broker) + err := sub.onEachPartition(partition, broker) + if err != nil { + glog.V(0).Infof("subscriber %s/%s/%s partition %+v at %v: %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, sub.SubscriberConfig.ConsumerGroup, partition, broker, err) + } + }(assigned.Partition, assigned.Broker) + } + + wg.Wait() +} + +func (sub *TopicSubscriber) onEachPartition(partition *mq_pb.Partition, broker string) error { + // connect to the partition broker + return pb.WithBrokerGrpcClient(true, broker, sub.SubscriberConfig.GrpcDialOption, func(client mq_pb.SeaweedMessagingClient) error { + subscribeClient, err := client.SubscribeMessage(context.Background(), &mq_pb.SubscribeMessageRequest{ + Message: &mq_pb.SubscribeMessageRequest_Init{ + Init: &mq_pb.SubscribeMessageRequest_InitMessage{ + ConsumerGroup: sub.SubscriberConfig.ConsumerGroup, + ConsumerId: sub.SubscriberConfig.ConsumerGroupInstanceId, + Topic: &mq_pb.Topic{ + Namespace: sub.ContentConfig.Namespace, + Name: sub.ContentConfig.Topic, + }, + PartitionOffset: &mq_pb.PartitionOffset{ + Partition: partition, + StartTsNs: sub.alreadyProcessedTsNs, + StartType: mq_pb.PartitionOffsetStartType_EARLIEST_IN_MEMORY, + }, + Filter: sub.ContentConfig.Filter, + }, + }, + }) + + if err != nil { + return fmt.Errorf("create subscribe client: %v", err) + } + + glog.V(0).Infof("subscriber %s/%s/%s connected to partition %+v at %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, sub.SubscriberConfig.ConsumerGroup, partition, broker) + + if sub.OnCompletionFunc != nil { + defer sub.OnCompletionFunc() + } + defer func() { + subscribeClient.SendMsg(&mq_pb.SubscribeMessageRequest{ + Message: &mq_pb.SubscribeMessageRequest_Ack{ + Ack: &mq_pb.SubscribeMessageRequest_AckMessage{ + Sequence: 0, + }, + }, + }) + subscribeClient.CloseSend() + }() + + for { + // glog.V(0).Infof("subscriber %s/%s/%s waiting for message", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, sub.SubscriberConfig.ConsumerGroup) + resp, err := subscribeClient.Recv() + if err != nil { + return fmt.Errorf("subscribe recv: %v", err) + } + if resp.Message == nil { + glog.V(0).Infof("subscriber %s/%s/%s received nil message", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, sub.SubscriberConfig.ConsumerGroup) + continue + } + switch m := resp.Message.(type) { + case *mq_pb.SubscribeMessageResponse_Data: + shouldContinue, processErr := sub.OnEachMessageFunc(m.Data.Key, m.Data.Value) + if processErr != nil { + return fmt.Errorf("process error: %v", processErr) + } + sub.alreadyProcessedTsNs = m.Data.TsNs + if !shouldContinue { + return nil + } + case *mq_pb.SubscribeMessageResponse_Ctrl: + // glog.V(0).Infof("subscriber %s/%s/%s received control %+v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, sub.SubscriberConfig.ConsumerGroup, m.Ctrl) + if m.Ctrl.IsEndOfStream || m.Ctrl.IsEndOfTopic { + return io.EOF + } + } + } + + return nil + }) +} diff --git a/weed/mq/client/sub_client/lookup.go b/weed/mq/client/sub_client/lookup.go deleted file mode 100644 index b6d2a8c53..000000000 --- a/weed/mq/client/sub_client/lookup.go +++ /dev/null @@ -1,34 +0,0 @@ -package sub_client - -import ( - "context" - "fmt" - "github.com/seaweedfs/seaweedfs/weed/pb" - "github.com/seaweedfs/seaweedfs/weed/pb/mq_pb" -) - -func (sub *TopicSubscriber) doLookup(brokerAddress string) error { - err := pb.WithBrokerGrpcClient(true, - brokerAddress, - sub.SubscriberConfig.GrpcDialOption, - func(client mq_pb.SeaweedMessagingClient) error { - lookupResp, err := client.LookupTopicBrokers(context.Background(), - &mq_pb.LookupTopicBrokersRequest{ - Topic: &mq_pb.Topic{ - Namespace: sub.ContentConfig.Namespace, - Name: sub.ContentConfig.Topic, - }, - IsForPublish: false, - }) - if err != nil { - return err - } - sub.brokerPartitionAssignments = lookupResp.BrokerPartitionAssignments - return nil - }) - - if err != nil { - return fmt.Errorf("lookup topic %s/%s: %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, err) - } - return nil -} diff --git a/weed/mq/client/sub_client/process.go b/weed/mq/client/sub_client/process.go deleted file mode 100644 index b6bdb14ee..000000000 --- a/weed/mq/client/sub_client/process.go +++ /dev/null @@ -1,85 +0,0 @@ -package sub_client - -import ( - "context" - "fmt" - "github.com/seaweedfs/seaweedfs/weed/pb" - "github.com/seaweedfs/seaweedfs/weed/pb/mq_pb" - "sync" -) - -func (sub *TopicSubscriber) doProcess() error { - var wg sync.WaitGroup - for _, brokerPartitionAssignment := range sub.brokerPartitionAssignments { - brokerAddress := brokerPartitionAssignment.LeaderBroker - grpcConnection, err := pb.GrpcDial(context.Background(), brokerAddress, true, sub.SubscriberConfig.GrpcDialOption) - if err != nil { - return fmt.Errorf("dial broker %s: %v", brokerAddress, err) - } - brokerClient := mq_pb.NewSeaweedMessagingClient(grpcConnection) - subscribeClient, err := brokerClient.Subscribe(context.Background(), &mq_pb.SubscribeRequest{ - Message: &mq_pb.SubscribeRequest_Init{ - Init: &mq_pb.SubscribeRequest_InitMessage{ - ConsumerGroup: sub.SubscriberConfig.GroupId, - ConsumerId: sub.SubscriberConfig.GroupInstanceId, - Topic: &mq_pb.Topic{ - Namespace: sub.ContentConfig.Namespace, - Name: sub.ContentConfig.Topic, - }, - Partition: &mq_pb.Partition{ - RingSize: brokerPartitionAssignment.Partition.RingSize, - RangeStart: brokerPartitionAssignment.Partition.RangeStart, - RangeStop: brokerPartitionAssignment.Partition.RangeStop, - }, - Filter: sub.ContentConfig.Filter, - Offset: &mq_pb.SubscribeRequest_InitMessage_StartTimestampNs{ - StartTimestampNs: sub.alreadyProcessedTsNs, - }, - }, - }, - }) - if err != nil { - return fmt.Errorf("create subscribe client: %v", err) - } - wg.Add(1) - go func() { - defer wg.Done() - if sub.OnCompletionFunc != nil { - defer sub.OnCompletionFunc() - } - defer func() { - subscribeClient.SendMsg(&mq_pb.SubscribeRequest{ - Message: &mq_pb.SubscribeRequest_Ack{ - Ack: &mq_pb.SubscribeRequest_AckMessage{ - Sequence: 0, - }, - }, - }) - subscribeClient.CloseSend() - }() - for { - resp, err := subscribeClient.Recv() - if err != nil { - fmt.Printf("subscribe error: %v\n", err) - return - } - if resp.Message == nil { - continue - } - switch m := resp.Message.(type) { - case *mq_pb.SubscribeResponse_Data: - if !sub.OnEachMessageFunc(m.Data.Key, m.Data.Value) { - return - } - sub.alreadyProcessedTsNs = m.Data.TsNs - case *mq_pb.SubscribeResponse_Ctrl: - if m.Ctrl.IsEndOfStream || m.Ctrl.IsEndOfTopic { - return - } - } - } - }() - } - wg.Wait() - return nil -} diff --git a/weed/mq/client/sub_client/subscribe.go b/weed/mq/client/sub_client/subscribe.go index 370f5aa3c..df62ea674 100644 --- a/weed/mq/client/sub_client/subscribe.go +++ b/weed/mq/client/sub_client/subscribe.go @@ -1,48 +1,11 @@ package sub_client -import ( - "fmt" - "github.com/seaweedfs/seaweedfs/weed/util" - "io" - "log" - "time" -) - // Subscribe subscribes to a topic's specified partitions. // If a partition is moved to another broker, the subscriber will automatically reconnect to the new broker. func (sub *TopicSubscriber) Subscribe() error { - index := -1 - util.RetryUntil("subscribe", func() error { - index++ - index = index % len(sub.bootstrapBrokers) - // ask balancer for brokers of the topic - if err := sub.doLookup(sub.bootstrapBrokers[index]); err != nil { - return fmt.Errorf("lookup topic %s/%s: %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, err) - } - if len(sub.brokerPartitionAssignments) == 0 { - if sub.waitForMoreMessage { - time.Sleep(1 * time.Second) - return fmt.Errorf("no broker partition assignments") - } else { - return nil - } - } - // treat the first broker as the topic leader - // connect to the leader broker + // loop forever + sub.doKeepConnectedToSubCoordinator() - // subscribe to the topic - if err := sub.doProcess(); err != nil { - return fmt.Errorf("subscribe topic %s/%s: %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, err) - } - return nil - }, func(err error) bool { - if err == io.EOF { - log.Printf("subscriber %s/%s: %v", sub.ContentConfig.Namespace, sub.ContentConfig.Topic, err) - sub.waitForMoreMessage = false - return false - } - return true - }) return nil } diff --git a/weed/mq/client/sub_client/subscriber.go b/weed/mq/client/sub_client/subscriber.go index 9b96b14cb..9adc5197e 100644 --- a/weed/mq/client/sub_client/subscriber.go +++ b/weed/mq/client/sub_client/subscriber.go @@ -7,10 +7,10 @@ import ( ) type SubscriberConfiguration struct { - ClientId string - GroupId string - GroupInstanceId string - GroupMinimumPeers int32 + ClientId string + ConsumerGroup string + ConsumerGroupInstanceId string + GroupMinimumPeers int32 GroupMaximumPeers int32 BootstrapServers []string GrpcDialOption grpc.DialOption @@ -23,12 +23,17 @@ type ContentConfiguration struct { StartTime time.Time } -type OnEachMessageFunc func(key, value []byte) (shouldContinue bool) +type ProcessorConfiguration struct { + ConcurrentPartitionLimit int // how many partitions to process concurrently +} + +type OnEachMessageFunc func(key, value []byte) (shouldContinue bool, err error) type OnCompletionFunc func() type TopicSubscriber struct { SubscriberConfig *SubscriberConfiguration ContentConfig *ContentConfiguration + ProcessorConfig *ProcessorConfiguration brokerPartitionAssignments []*mq_pb.BrokerPartitionAssignment OnEachMessageFunc OnEachMessageFunc OnCompletionFunc OnCompletionFunc @@ -37,10 +42,11 @@ type TopicSubscriber struct { alreadyProcessedTsNs int64 } -func NewTopicSubscriber(bootstrapBrokers []string, subscriber *SubscriberConfiguration, content *ContentConfiguration) *TopicSubscriber { +func NewTopicSubscriber(bootstrapBrokers []string, subscriber *SubscriberConfiguration, content *ContentConfiguration, processor ProcessorConfiguration) *TopicSubscriber { return &TopicSubscriber{ SubscriberConfig: subscriber, ContentConfig: content, + ProcessorConfig: &processor, bootstrapBrokers: bootstrapBrokers, waitForMoreMessage: true, alreadyProcessedTsNs: content.StartTime.UnixNano(), |
