Grpc Java server test for ServerInterceptors

55 views
Skip to first unread message

John Wilson

unread,
Nov 27, 2023, 6:02:36 PM11/27/23
to grpc.io
Hi Grpc team! 
I have a ServerInterceptor instance for my grpc server, it does something like this:

@Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
            ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        Context context = Context.current();
        .... // more code here 
        context = context.withValue(USER_ID, "my-user-id");
        return Contexts.interceptCall(context, call, headers, next);
    }

and in my service method I get access to the userId using smth like this:

USER_ID.get()


I have some questions:
Is this implementation correct?
Is this thread safe?
Is there any way to test that implementation?
Is there any documentation that I can check to understand how Threads are handled by the grpc server?

Thanks in advance! :) 

Edu-

John Wilson

unread,
Nov 27, 2023, 6:02:37 PM11/27/23
to grpc.io

Eric Anderson

unread,
Nov 28, 2023, 10:36:22 AM11/28/23
to John Wilson, grpc.io
On Mon, Nov 27, 2023 at 3:02 PM John Wilson <johnyw...@gmail.com> wrote:
Is this implementation correct?

Looks fine.

Is this thread safe?

Context is immutable (although the values could be mutable, but then you'd be responsible for synchronization). And the "current" Context is stored in a ThreadLocal. So, yes, it is thread-safe.

Is there any way to test that implementation?

The way to give you the most confidence would be using in-process transport, like other tests. In your test case you'd make a test service implementation that does USER_ID.get(), and then send it an RPC. You may find grpc-testing-proto (io.grpc.testing.protobuf) useful, as it has a simple service you can implement for testing. That will use multiple callbacks (within the stub) and give you the highest confidence.

It'd also be possible to test the interceptor "bare" by implementing a ServerCallHandler. io.grpc.testing.TestMethodDescriptors.voidMethod() is available as a MethodDescriptor. ServerCall could be a ForwardingServerCall whose delegate() throws, and then you override any methods your test needs. That may give you less confidence in your understanding of Contexts.interceptCall().

Is there any documentation that I can check to understand how Threads are handled by the grpc server?

There's some docs on ServerCall.Listener. Basically, there's multiple callbacks, and they won't be called concurrently but may be called from different threads. So if you set a ThreadLocal in one, you may not see it in the next. Contexts.interceptCall sets the ThreadLocal, calls the callback, and then unsets the ThreadLocal before returning.
Reply all
Reply to author
Forward
0 new messages