0

(disclaimer: I'm dabbling in grpc)

I've got an object that I'd like to associate with every request, initializeing it at the start of a request and closeing it once the request is done.

Currently I'm achieving this by using two ServerInterceptors, the first to populate the object into the Context and the second to intercept onReady and onComplete to initialize and close the object respectively.

PopulateObjectServerInterceptor:

public class FooBarInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
    FooBar foobar = FooBar.create(foo, bar);
    Context ctx = Context.current().withValue(Constants.FOO_BAR, foobar);

    return Contexts.interceptCall(ctx, call, headers, next);
}

RequestLifecycleInterceptor

public class FooBarLifecycleServerInterceptor implements ServerInterceptor {
    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
                                                                 Metadata headers,
                                                                 ServerCallHandler<ReqT, RespT> next) {

        final ServerCall.Listener<ReqT> original = next.startCall(call, headers);

        return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(original) {
            @Override
            public void onReady() {
                FooBar foobar = (FooBar) Context.key("foobarname").get();
                foobar.initialize()
                super.onReady();
            }

            @Override
            public void onMessage(final ReqT message) {
                FooBar foo = (FooBar) Context.key("foobar").get();
                foobar.someaction()
                super.onMessage(message);
            }

            @Override
            public void onComplete() {
                FooBar foo = (FooBar) Context.key("foobar").get();
                foobar.close()
                super.onComplete();
            }
        }
    } 
}

Is this the correct/recommended way? I'm wondering whether I can do this with just the one interceptor...

  • I am doing something very similar, but using `ThreadLocal`. This is the answer, it's for a REST Controller, not a Grpc service, but it works for Grpc too: https://stackoverflow.com/questions/60488621/springboot-read-fields-from-request-and-set-it-in-every-response-in-rest-contro/60540103#60540103 – daltonfury42 Mar 06 '20 at 11:01

1 Answers1

0

What you're doing looks fine. Another way is to create the object in the FooBarLifecycleServerInterceptor and avoid using Context in the first place, but there may be some other requirements not illustrated in your example.

Note: onReady may not do what you think it does. If the idea is to call initialize at the start of each server call, I think you should just do it when the call interception happens.

One of onComplete and onCancel will be called, so you should also call close() when onCancel is called.

Spencer
  • 77
  • 1