[grpc-java] Managing per-call database transactions

577 views
Skip to first unread message

pa...@muun.io

unread,
Nov 9, 2015, 10:27:31 AM11/9/15
to grpc.io
Hi,

I'm setting up a web service using grpc-java and hibernate. I want to start a transaction whenever I receive a new call from a client and commit/abort it after it.

As far as I understand I should do something like this:

public class DatabaseTransactionInterceptor implements ServerInterceptor {
    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
            MethodDescriptor<ReqT, RespT> methodDescriptor,
            ServerCall<RespT> serverCall,
            Metadata metadata,
            ServerCallHandler<ReqT, RespT> serverCallHandler) {

        // Initiate transaction and add it to grpc context

        return new SimpleForwardingServerCallListener<ReqT>(serverCallHandler.startCall(
                methodDescriptor, serverCall, metadata)) {

            @Override
            public void onCancel() {
                super.onCancel();

                // Abort transaction and remove it from grpc context
            }

            @Override
            public void onComplete() {
                super.onComplete();

                // Commit transaction and remove it from grpc context
            }
        };
    }
}

And then get it from the context on the implementation of the services and use it.

My problem is that it one of the implementations throws onComplete() is called instead of onCancel(), so I guess I'm getting something wrong.

Can you give me any hint about who to do this?

Thanks,

Pato

Eric Anderson

unread,
Dec 1, 2015, 9:35:41 PM12/1/15
to pa...@muun.io, grpc.io
On Mon, Nov 9, 2015 at 7:27 AM, <pa...@muun.io> wrote:
As far as I understand I should do something like this:
<snip>

The code could be reasonable depending on what your calls look like. You should be informed that the client isn't guaranteed to receive the server's response (even if onComplete() is called). onComplete() means the server considers the RPC done, so the response was sent, but that doesn't necessarily mean that 1) it was received by the client, 2) that the client didn't error when processing the response.

My problem is that it one of the implementations throws onComplete() is called instead of onCancel(), so I guess I'm getting something wrong.

When you say "one of the implementations," you mean that if a client throws an exception you still get onComplete()? That is believable given my comments above, especially if doing single request/single response.

If you use streaming, the client can keep the stream open until it completes processing the response from the server, then close its side of the stream (halfClose() in ClientCall or onCompleted() in StreamObserver). That delays the completion of the call until the client completed processing (the halfClose() ends up acting as an acknowledgement). When the server sees the client complete, then it completes its side of the call (close() in ServerCall or onCompleted() in StreamObserver). Note that this "trick" will work with DatabaseTransactionInterceptor as-is; it wouldn't need to be modified.

pa...@muun.io

unread,
Dec 2, 2015, 1:18:15 PM12/2/15
to grpc.io, pa...@muun.io
Thanks for answering Eric,


On Tuesday, December 1, 2015 at 11:35:41 PM UTC-3, Eric Anderson wrote:
When you say "one of the implementations," you mean that if a client throws an exception you still get onComplete()?

Sorry for not stating that clearly. I was talking about the server-side here, and by implementation I was meaning the implementations of a service's rpc. Something like:

public class ExampleService implements ExampleGrpc.Example {
 
@Override
 
public void exampleRpc(Req req, StreamObserver<Res> streamObserver) {
   
throw new RuntimeException();
 
}
}

When exampleRpc is executed, the SimpleForwardingServerCallListener's onComplete is still called, and that seems to be wrong/odd.

Anyway, I moved to a different approach to handle what I was trying to do, with a little bit of boilerplate, but more explicit and easier to follow.

Thanks,

Pato
Reply all
Reply to author
Forward
0 new messages