繁体   English   中英

go和grpc如何解决pub-sub问题?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM