admin管理员组

文章数量:1122927

I have a Spring Boot application serving HTTP requests in a multitenant architecture. For HTTP requests, client identity is extracted from a header and stored in a ThreadLocal. Since Tomcat ensures a single request is served by a single thread, this approach works well.

Now, the application is being extended to serve gRPC requests (unary calls only). I understand there are concerns about using ThreadLocal in gRPC, even for unary calls. However, my testing shows no issues so far.

To address potential concerns, I explored using the gRPC Context API to propagate request-scoped data, such as client identity, across multiple server interceptors. Below is an example of my implementation:

Example Implementation:

@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
    ServerCall<ReqT, RespT> serverCall,
    Metadata metadata,
    ServerCallHandler<ReqT, RespT> serverCallHandler
) {
    Context ctx = Context.current()
        .withValue(GrpcContextStorage.grpcRequestKey, Boolean.TRUE)
        .withValue(GrpcContextStorage.grpcRequestDateTimeKey, DateTimeUtil.getCurrentLocalTime());

    ServerCall.Listener<ReqT> listener = Contexts.interceptCall(ctx, serverCall, metadata, serverCallHandler);

    return new InterceptorForwardingCallListener<>(listener) {
        @Override
        public void onCancel() {
            try {
                super.onCancel();
            } catch (Exception exe) {
                _logger.error("Error in onCancel: " + exe.getMessage(), exe);
                throw exe;
            } finally {
                MDC.clear(); // Custom cleanup logic
            }
        }

        @Override
        public void onComplete() {
            try {
                super.onComplete();
            } catch (Exception exe) {
                _logger.error("Error in onComplete: " + exe.getMessage(), exe);
                throw exe;
            } finally {
                MDC.clear(); // Custom cleanup logic
            }
        }
    };
}

Specific Questions:

  1. Using ThreadLocal in gRPC Unary Calls:

    Is it acceptable to use ThreadLocal for storing request-scoped data in gRPC unary calls? If not, why is it discouraged, considering the synchronous nature of unary calls?

  2. Using gRPC Context for Propagation:

    In the implementation above, does the creation of a new Context object using Context.withValue() ensure proper isolation of data between requests? Is manual cleanup of the previous Context required, or does gRPC handle this automatically? How can I ensure client-specific data stored in the Context is not inadvertently leaked or reused in subsequent requests?

  3. MDC and Logging in gRPC Unary Calls:

    Is it appropriate to use MDC (which relies on ThreadLocal) for logging context in gRPC unary calls? If so, is overriding onComplete() and onCancel() sufficient to ensure proper cleanup of MDC after the request lifecycle? Should other methods like onHalfClose() be overridden to handle edge cases? If MDC is discouraged, what alternative approach should I use for propagating logging context across interceptors?

本文标签: javaHow to manage requestscoped data and MDC effectively in gRPC unary callsStack Overflow