[gRPC-Java] Pass context or header information to parseRequest on server side

61 views
Skip to first unread message

R Chinmay

unread,
Feb 12, 2024, 11:07:03 AMFeb 12
to grpc.io

I have a custom implementation of request marshaller (overriding io.grpc.MethodDescriptor.Marshaller) which I want to use, but I would need context information related to the microservice call (specifically microservice method name being invoked). I tried populating it in ServerInterceptor's interceptCall. My interceptor code looks like this:

​@Override
public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
  Context context = Context.current().withValue(MS_METHOD_NAME, call.getMethodDescriptor().getFullMethodName());
   return Contexts.interceptCall(context, serverCall, metadata, serverCallHandler);
}

But the context populated does not persist when unmarshalling of the request stream takes place.

This is because io.grpc.internal.ServerImpl.ServerTransportListenerImpl#streamCreatedInternal creates new io.grpc.internal.ServerImpl.JumpToApplicationThreadServerStreamListener and populates context using io.grpc.internal.ServerImpl.ServerTransportListenerImpl#createContext which just adds deadline and serverImpl instance fields over rootContext. So, the information I populated was not available during unmarshalling. Also, populating it in onMessage would not be useful too, since io.grpc.internal.ServerCallImpl.ServerStreamListenerImpl#messagesAvailableInternal uses 

​listener.onMessage(call.method.parseRequest(message));

so parseRequest executes before onMessage is triggered.

Is there some way to pass context information to marshaller, or maybe use method name there. I am constructing methodDescriptor using io.grpc.MethodDescriptor.Builder

Sergii Tkachenko

unread,
Feb 15, 2024, 2:58:15 PMFeb 15
to grpc.io
You are correct, the Marshaller won't be able to access the Context from the interceptor. Though not exactly for the reasons you mentioned.
Unmarshalling happens prior to `ServerCall.Listener.onMessage` callback is executed: 

1. io.grpc.MethodDescriptor.Marshaller unmarshaller the message -->
2. Contexts.interceptCall interceptor (ContextualizedServerCallListener) restores the contexts -->
3. ServerCall.Listener.onMessage callbacks are executed (with the context attached).

To answer your question, could you please provide a bit more info on what you're trying to achieve? Why do you need microservice method name in the marshaller?
There are a few possible approaches, but it really depends on your goals.

Best Regards,
Sergii

R Chinmay

unread,
Feb 19, 2024, 9:37:49 AMFeb 19
to grpc.io
Thanks for your reply.
Since the exception from the marshaller in server does not reach the client, and the exception logged in server does not contain any information about microservice method which was invoked, I wanted to log microservice method name along with the parsing exception, so that we can track the microservice methods which are incompatible with the new marshaller and allow fallback to default marshaller (which is comparitively slower) for further calls.

Sergii Tkachenko

unread,
Feb 21, 2024, 5:41:08 PMFeb 21
to grpc.io
Thank you for the detailed explanation.

Since the only thing you need is the method name, consider adding a methodName parameter to your marshaller class. Then, when building the service definition, you can create an instance of your marshaller per method, and provide the method name as a constructor/builder argument.
Would this solution work for you? If not, I'd be curious to know why.

- Sergii


Reply all
Reply to author
Forward
0 new messages