[grpc-java] global exception handler on client-side

1,328 views
Skip to first unread message

eval...@exadel.com

unread,
Sep 29, 2017, 9:19:27 AM9/29/17
to grpc.io
With grpc 0.15.0 some time ago I implemented client side exception handler via spring aspect. It converts StatusRuntimeException from the upstream service into my own domain exception and re-throws it. I find it quite convenient as throughout the code I can catch particular exceptions I'm interested in instead of always catching StatusRuntimeException.

I consider switching to the latest (1.6.1) version, and the problem is that client stubs have been made final and it is no longer possible to use aspects.
The only (and ugly) solution is to do exception conversion in cancel method of SimpleForwardingClientCall(called from catch block in blockingUnaryCall). But in my understanding cancel method is not supposed to throw exceptions, especially in case when cancel is called by the client code itself.
For server-streaming calls it is not possible to catch-and-rethrow the exception thrown from iterator at all. With 0.15.0 I wrap returned iterator and override hasNext method to catch and re-throw the exception.

Has anyone tried to solve the same problem?
Maybe there are plans to include support for such cases in grpc?

Thank you in advance.

Carl Mastrangelo

unread,
Oct 3, 2017, 12:31:14 AM10/3/17
to grpc.io
How many stubs / channels do you have?   Why not just do the conversion in an interceptor?

eval...@exadel.com

unread,
Oct 3, 2017, 3:18:21 AM10/3/17
to grpc.io
I have 1-2 channels and 1-12 stubs in 5 applications. Subs have up to 30 methods, so I don't really consider writing wrappers manually as a viable option.
> Why not just do the conversion in an interceptor?
I'd be happy to know how. As far as I can see all interceptor methods(except cancel) can be called in other thread, even if they are called in the same thread, all exceptions are either swallowed or wrapped into StatusRuntimeException.


eval...@exadel.com

unread,
Feb 9, 2018, 8:52:34 AM2/9/18
to grpc.io
Hi!

Any updates on this?

I checked version 1.9.0 and still don't see a way to do exception conversion in an interceptor. 
I now think of writing my own wrappers for all blocking stubs to perform exception conversion. That would allow not to check status codes across the application and just catch specific exceptions where needed.
However, having the ability to define an exception transformer globally for grpc client would of course make life easier.

Thanks

Carl Mastrangelo

unread,
Feb 14, 2018, 2:01:36 PM2/14/18
to grpc.io
No updates.   If you can upload your code somewhere, it would be clearer why the interceptor wouldn't work.  

eval...@exadel.com

unread,
Mar 1, 2018, 4:10:36 AM3/1/18
to grpc.io
Here's the example that shows what I'm trying to achieve - https://github.com/cartmanez/grpc-java-by-example/tree/master/error-handling-example
The idea is the following:
I have a set of domain exception known by each microservice. There's a mapping domain exception <-> StatusRuntimeException
Server automatically converts domain exception into StatusRuntimeException. That's done by server interceptor.
And I'd like to convert it back to domain exception on the client side, so that calling code does not need to worry about StatusRuntimeException at all and only works with domain exceptions.

Thanks in advance.

Regards,
Eduard

Carl Mastrangelo

unread,
Mar 1, 2018, 1:45:20 PM3/1/18
to grpc.io
You need to add a ClientInterceptor too.  It will provide a listener which overrides the onClose(Status, Metadata) method of a ClientCall.Listener.    There, you can check for your metadata row added by the server, and return the proper type of error to the next listener in your interceptor chain.

eval...@exadel.com

unread,
Mar 1, 2018, 2:35:58 PM3/1/18
to grpc.io
Carl,

thanks for reply.

However, I'm a bit confused as I don't see a way to return my custom exception from the listener to the calling code.
Throwing an exception from onClose simply swallows the exception and makes the call hang forever.
super.onClose() only accepts status and trailers. So, no way to pass my custom exception.

I added client interceptor to the example project.

Regards,
Eduard

Carl Mastrangelo

unread,
Mar 29, 2018, 12:00:07 PM3/29/18
to grpc.io
Point of clarification:   Stubs throw exceptions, Calls and Call.Listeners do not.   The stubs wrap the calls/listeners and convert Status and Metadata trailers into an exception, but you don't have to.   

In the code you linked, you can attach a cause to the Status and pass that through in your interceptor.   The outer most exception the stub will get is a StatusRuntimeException IIRC, but you can walk the causal chain to get at your underlying.  (we don't really /throw/ other people's exceptions)

eval...@exadel.com

unread,
Apr 14, 2018, 8:49:32 AM4/14/18
to grpc.io
This is exactly what I'm trying to avoid - unwrapping StatusRuntimeException each time I expect an exception or each time I call a grpc stub method.
What I want is to setup an exception converter once, and have it applied automatically to all grpc calls.

Eric Anderson

unread,
Apr 16, 2018, 7:31:50 PM4/16/18
to eval...@exadel.com, grpc.io
On Sat, Apr 14, 2018 at 5:49 AM, evaliauka via grpc.io <grp...@googlegroups.com> wrote:
What I want is to setup an exception converter once, and have it applied automatically to all grpc calls.

grpc-java doesn't support this, and it would be a bit weird because it changes the API. Maybe it could be a feature/configuration of the stub, as long as you only want to throw RuntimeExceptions. But it also seems like it would bring confusion when used. I do understand the annoyance of dealing with less-than-ideally-convenient exception types, but it seems "that's Java."

The only real way to do this today is make your own stub type, and that would imply code generation. You can make a "poor man's" stub by having your users pass your code a MethodDescriptor (obtained via YourServiceGrpc.getYourMethod()), at which point you could do any conversion logic and then call the stub utilities like ClientCalls.blockingUnaryCall().

eval...@exadel.com

unread,
Jan 10, 2019, 3:13:52 AM1/10/19
to grpc.io
Is ClientCalls class part of public API? I.e. am I safe to assume that it won't have breaking changes as long as I'm using grpc 1.X?

Kun Zhang

unread,
Jan 10, 2019, 8:39:53 PM1/10/19
to grpc.io
Yes it's public API and we guarantee it won't break within the same major version.

eval...@exadel.com

unread,
Feb 1, 2019, 5:57:06 AM2/1/19
to grpc.io
Thanks!
Reply all
Reply to author
Forward
0 new messages