英文:
What's the best way to determine when an RPC session ends using a StreamClientInterceptor?
问题
在编写StreamClientInterceptor函数时,确定调用者何时完成RPC的最佳方法是什么?对于一元拦截器或在服务器端,您会收到执行RPC的handler,这是很明显的。但是在客户端,您返回一个ClientStream,调用者与之交互,这时候该如何确定呢?
其中一个使用案例是在OpenTracing中进行仪表化,目标是在RPC的开始和结束时启动和完成一个span。
我正在研究的一种策略是让流拦截器返回一个装饰过的ClientStream。这个新的ClientStream会在任何接口方法Header
、CloseSend
、SendMsg
、RecvMsg
返回错误或Context
被取消时,将RPC视为已完成。此外,它还在RecvMsg
方法中添加了以下逻辑:
func (cs *DecoratedClientStream) RecvMsg(m interface{}) error {
err := cs.ClientStream.RecvMsg(m)
if err == io.EOF {
// 将RPC视为已完成
return err
} else if err != nil {
// 将RPC视为已完成
return err
}
if !cs.isResponseStreaming {
// 将RPC视为已完成
}
return err
}
在大多数情况下,这种方法是有效的。但是我了解到,如果调用者知道结果将是io.EOF
,它并不需要调用Recv
(参见https://stackoverflow.com/questions/42915337/are-you-required-to-call-recv-until-you-get-io-eof-when-interacting-with-grpc-cl/42939914#42939914),所以它并不适用于所有情况。有没有更好的方法来实现这个目标?
英文:
When writing a StreamClientInterceptor function, what's the best way to determine when an invoker finishes the RPC? This is straightforward enough with unary interceptors or on the server-side where you're passed a handler that performs the RPC, but it's not clear how best to do this on the client-side where you return a ClientStream that the invoker then interacts with.
One use case for this is instrumenting OpenTracing, where the goal is to start and finish a span to mark the beginning and end of the RPC.
A strategy I'm looking into is having the stream interceptor return a decorated ClientStream. This new ClientStream considers the RPC to have completed if any of the interface methods Header
, CloseSend
, SendMsg
, RecvMsg
return an error or if the Context
is cancelled. Additionally, it adds this logic to RecvMsg
:
func (cs *DecoratedClientStream) RecvMsg(m interface{}) error {
err := cs.ClientStream.RecvMsg(m)
if err == io.EOF {
// Consider the RPC as complete
return err
} else if err != nil {
// Consider the RPC as complete
return err
}
if !cs.isResponseStreaming {
// Consider the RPC as complete
}
return err
}
It would work in most cases, but my understanding is that an invoker isn't required to call Recv
if it knows the result will be io.EOF
(See https://stackoverflow.com/questions/42915337/are-you-required-to-call-recv-until-you-get-io-eof-when-interacting-with-grpc-cl/42939914#42939914), so it wouldn't work in all cases. Is there a better way to accomplish this?
答案1
得分: 3
我遇到了一个非常类似的问题,我想要追踪流式的 gRPC 调用。除了像你自己提到的那样对流进行装饰之外,我没有找到一个好的方法来检测流的结束。直到我发现了 grpc-go 提供的 stats hooks(https://godoc.org/google.golang.org/grpc/stats)。尽管 stats API 的目的是收集有关 RPC 调用的统计信息,但它提供的 hooks 对于追踪也非常有帮助。
如果你仍然在寻找追踪流式调用的方法,我编写了一个使用 stats hooks 对 gRPC 进行 OpenTracing 仪器化的库:https://github.com/charithe/otgrpc。然而,请注意,这种方法可能不适用于创建长时间运行的流的系统。
英文:
I had a very similar issue where I wanted to trace streaming gRPC calls. Other than decorating the stream as you mentioned yourself, I was not able to find a good way to detect the end of streams. That is, until I came across the stats hooks provided by grpc-go (https://godoc.org/google.golang.org/grpc/stats). Even though the stats API is meant for gathering statistics about the RPC calls, the hooks it provides are very helpful for tracing as well.
If you're still looking for a way to trace streaming calls, I have written a library for OpenTracing instrumentation of gRPC, using the stats hooks:
https://github.com/charithe/otgrpc. However, please bear in mind that this approach is probably not suitable for systems that create long-lived streams.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论