Golang Go语言中gRpc有无方法可以手动发送一个error?
某个 grpc 转发服务遇到一个问题,一次双向 stream 的请求,中间可能会有两个负责转发的节点,大概是:
client-->proxyA-->proxyB-->server
proxy 的处理过程是,来自请求发起方(client 方向)的 stream 是 grpc.ServerStream ,之后根据路由表建立向 server 端方向的服务器的 ClientStream 。一个 goroutine 负责从 client 收消息然后发给 server ,一个负责从 server 收消息发给 client 。
目前遇到的问题是,如果 server 返回 error 并关闭连接,proxyB 上负责接收 client 方向请求的 goroutine 会卡在 client 方向的 stream 的 RecvMsg 这里,需要接收一次来自 proxyA 的请求才能退出。同理,proxyA 也需要 client 发送一次请求才能退出。
结果就是当 server 出了问题,需要等 client 发送两次请求才能正常返回 error (第一次请求断开 proxyA 到 proxyB 的连接,第二次断开 client 到 proxyA 的连接)。更严重的是,第一次请求会一直阻塞在这里,直到超时后 context 被 cancel 掉。
我现在的想法是,能不能让 proxyB 在收到 server 返回的错误后手动给 proxyA 发送一个 error 以改善这一过程?毕竟不是所有的 stream 连接都能接受加心跳请求或是重试的,这对业务也是额外的负担。
Golang Go语言中gRpc有无方法可以手动发送一个error?
更多关于Golang Go语言中gRpc有无方法可以手动发送一个error?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
proxy 是四层的负载均衡吗,可以改成 7 层的负载均衡看看。
nginx 好像 1.20 版本就支持 grpc 的负载转发。
更多关于Golang Go语言中gRpc有无方法可以手动发送一个error?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
目前遇到的问题是,如果 server 返回 error 并关闭连接,proxyB 上负责接收 client 方向请求的 goroutine 会卡在 client 方向的 stream 的 RecvMsg 这里,需要接收一次来自 proxyA 的请求才能退出。同理,proxyA 也需要 client 发送一次请求才能退出。
=======================================================================
proxy 就是应该完全透传收到的请求阿。proxyB 都收到 server 的 error ,并且和 server 的连接都断开了,理所当然的 proxyB 应该和 proxyA 的连接也断开。
ps1:grpc 是长连接没办法做负载均衡的,不知道你为什么要用 proxy 来做?难道是网关?
ps2:proxyB 对长连接的处理直接用两个 io.copy 就完事了。任何一个 copy 出现问题,都可以手动断开两边的连接。
这明显是 proxy 实现的有问题吧
双向 stream 应该用同一个 ctx ?
在Go语言的gRPC框架中,确实可以手动发送一个错误给客户端。gRPC通过状态码(status codes)和状态消息(status messages)来实现这一功能。以下是如何在gRPC服务中手动发送错误的简要说明:
-
使用
status.Error
和status.FromError
: gRPC提供了google.golang.org/grpc/status
包,可以用来创建和处理错误。你可以使用status.Error
或status.FromError
来创建一个status.Status
对象,然后通过服务方法的返回值发送这个错误。 -
在服务方法中返回错误: 在你的gRPC服务方法中,你可以直接返回一个
status.Status
对象作为错误。这个对象会包含状态码和状态消息,它们会被自动序列化并发送给客户端。 -
示例代码:
import ( "context" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func (s *myService) MyRPCMethod(ctx context.Context, req *MyRequest) (*MyResponse, error) { // 假设有某种条件需要返回错误 if someCondition { return nil, status.Error(codes.InvalidArgument, "Invalid input provided") } // 正常处理逻辑 return &MyResponse{}, nil }
通过上述方法,你可以在gRPC服务中手动发送一个带有自定义错误信息的响应给客户端。