客户端断开连接时如何正确使用 ctx.Done()?

pen*_*olf 6 channel go grpc

如果客户端因网络错误而断开连接,则在我的情况下,服务器必须关闭 pub/sub 连接。我了解ctx.Done()功能,但不知道如何在我的情况下正确使用它。有人可以解释一下吗?

grpc-go:1.7.0

go版本go1.8.4

func (a *API) Notifications(in *empty.Empty, stream pb.Service_NotificationsServer) error {
    ctx := stream.Context()
    _, ok := user.FromContext(ctx)
    if !ok {
        return grpc.Errorf(codes.Unauthenticated, "user not found")
    }

    pubsub := a.redisClient.Subscribe("notifications")
    defer pubsub.Close()

    for {
        msg, err := pubsub.ReceiveMessage()
        if err != nil {
            grpclog.Warningf("Notifications: pubsub error: %v", err)
            return grpc.Errorf(codes.Internal, "pubsub error %v", err)
        }

        notification := &pb.Notification{}
        err = json.Unmarshal([]byte(msg.Payload), notification)
        if err != nil {
            grpclog.Warningf("Notifications: parse error: %v", err)
            continue
        }
        if err := stream.Send(notification); err != nil {
            grpclog.Warningf("Notifications: %v", err)
            return err
        }
        grpclog.Infof("Notifications: send msg %v", notification)
    }
}
Run Code Online (Sandbox Code Playgroud)

I15*_*159 1

您应该从调用者函数(或可以访问上下文的任何地方)取消上下文,并在Done()检查select语句时执行适当的操作。

Done 提供用于 select 语句

Done 返回一个通道,当应取消代表此上下文完成的工作时,该通道已关闭。如果此上下文永远无法取消,则 Done 可能会返回 nil。连续调用 Done 返回相同的值。

WithCancel 返回带有新 Done 通道的父级副本。当调用返回的取消函数或关闭父上下文的 Done 通道时(以先发生者为准),返回的上下文的 Done 通道将关闭。

取消此上下文会释放与其关联的资源,因此在此上下文中运行的操作完成后,代码应立即调用取消。

go func() {
    for {
        select {
        case <-ctx.Done():
            return // returning not to leak the goroutine
        case dst <- n:
            n++
        }
    }
}()
Run Code Online (Sandbox Code Playgroud)