3
votes

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 Are you required to call Recv until you get io.EOF when interacting with grpc.ClientStreams?), so it wouldn't work in all cases. Is there a better way to accomplish this?

1

1 Answers

3
votes

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.