Go gRPC服务器端Unary Call客户端连接终止检查方法咨询
Go gRPC Unary调用中检测客户端连接断开的方法
别被ServerStreaming的例子误导——Unary RPC里同样能用Context的Done()通道检查客户端是否断开连接,逻辑和流式调用完全通用。你的处理函数已经拿到了gRPC传递的context.Context,这个ctx会在客户端主动断开、请求超时或被取消时触发Done信号。
具体实现分三种场景:
1. 可中断的同步处理流程
如果长时间任务能拆成多个阶段,定期检查ctx状态:
func (*Server) EndpointName(ctx context.Context, in *pb.EndpointRequest) (*pb.EndpointResponse, error) { // 模拟分步骤执行的耗时操作 for step := 0; step < 10; step++ { select { case <-ctx.Done(): // 客户端已断开,返回标准gRPC取消错误 return nil, status.Error(codes.Canceled, "client connection closed") default: // 替换为你的实际业务处理逻辑 time.Sleep(30 * time.Second) } } return &pb.EndpointResponse{Result: "success"}, nil }
2. 异步处理流程(用goroutine执行任务)
如果任务是异步运行的,主goroutine同时监听ctx.Done()和任务结果:
func (*Server) EndpointName(ctx context.Context, in *pb.EndpointRequest) (*pb.EndpointResponse, error) { resultChan := make(chan *pb.EndpointResponse, 1) errChan := make(chan error, 1) // 启动goroutine执行长时间任务 go func() { res, err := yourLongRunningTask(in) if err != nil { errChan <- err return } resultChan <- res }() // 等待上下文取消或任务完成 select { case <-ctx.Done(): return nil, status.Error(codes.Canceled, ctx.Err().Error()) case err := <-errChan: return nil, err case res := <-resultChan: return res, nil } }
3. 无法中断的任务(仅在响应前检查)
如果任务本身不能被中断,至少在准备返回响应前检查一次ctx状态,避免白忙活:
func (*Server) EndpointName(ctx context.Context, in *pb.EndpointRequest) (*pb.EndpointResponse, error) { // 执行无法中断的耗时任务 res := doUninterruptibleWork(in) // 发送响应前确认客户端还在线 if ctx.Err() != nil { return nil, status.Error(codes.Canceled, "client disconnected before response sent") } return res, nil }
关键提示
- gRPC的Context是跨RPC类型通用的,不管Unary还是Streaming,客户端断开都会触发Done()。
- 返回错误时尽量用gRPC标准的
status.Error,客户端能拿到规范的错误码(比如codes.Canceled),方便统一处理。
内容的提问来源于stack exchange,提问作者Dodo14t
相关产品推荐
相关产品推荐

