[英]How to solve pub-sub problem in go and grpc?
在 go grpc 服务中,我有一个接收者(发布者)事件循环,发布者可以检测到它希望发送者停止。 但是通道原则说我们不应该在接收方关闭通道,而应该在发送方关闭。 应该怎么威胁?
情况如下。 想象一下聊天。 第一个客户端 - 订阅者 - 接收消息,由于 grpc 的限制,没有 goroutine 无法完成其流式传输。 第二个客户端 - 发布者正在发送消息进行聊天,因此它是另一个 goroutine。 您必须将消息从发布者传递给订阅者接收客户端,仅当订阅者未关闭其连接时(强制从接收者端关闭通道)
代码中的问题:
//1st client goroutine - subscriber
func (s *GRPCServer) WatchMessageServer(req *WatchMessageRequest, stream ExampleService_WatchMessageServer) error {
ch := s.NewClientChannel()
// natively blocks goroutine with send to its stream, until send gets an error
for {
msg, ok := <-ch
if !ok {
return nil
}
err := stream.Send(msg) // if this fails - we need to close ch from receiver side to "propagate" closing signal
if err != nil {
return err
}
}
}
//2nd client goroutine - publisher
func (s *GRPCServer) SendMessage(ctx context.Context, req *SendMessageRequest) (*emptypb.Empty, error) {
for i := range s.clientChannels {
s.clientChannels[i] <- req
// no way other than panic, to know when to remove channel from list. or need to make a wrapper with recover..
}
return nil
}
我最初通过搜索得到了线索,由于该答案,这里的答案中提供了解决方案的想法。
提供流解决方案示例代码,我猜它是通用发布-订阅问题的实现:
//1st client goroutine - subscriber
func (s *GRPCServer) WatchMessageServer(req *WatchMessageRequest, stream ExampleService_WatchMessageServer) error {
s.AddClientToBroadcastList(stream)
select {
case <-stream.Context().Done(): // stackoverflow promised that it would signal when client closes stream
return stream.Context().Err() // stream will be closed immediately after return
case <-s.ctx.Done(): // program shutdown
return s.ctx.Err()
}
}
//2nd client goroutine - publisher
func (s *GRPCServer) SendMessage(ctx context.Context, req *SendMessageRequest) (*emptypb.Empty, error) {
for i := range s.clientStreams {
err := s.clientStreams.Send(req)
if err != nil {
s.RemoveClientFromBroadcastList(s.clientStreams[i])
}
}
return nil
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.