In gRPC , how to add a global exception interceptor that intercepts any RuntimeException
and propagate meaningful information to the client ?
for example , a divide
method may throw ArithmeticException
with / by zero
message . In the server side , I may write :
@Override
public void divide(DivideRequest request, StreamObserver<DivideResponse> responseObserver) {
int dom = request.getDenominator();
int num = request.getNumerator();
double result = num / dom;
responseObserver.onNext(DivideResponse.newBuilder().setValue(result).build());
responseObserver.onCompleted();
}
If the client passes denominator = 0 , it will get :
Exception in thread "main" io.grpc.StatusRuntimeException: UNKNOWN
And the server outputs
Exception while executing runnable io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$2@62e95ade
java.lang.ArithmeticException: / by zero
The client doesn't know what's going on.
If I want to pass / by zero
message to client , I have to modify server to :
(as described in this question )
try {
double result = num / dom;
responseObserver.onNext(DivideResponse.newBuilder().setValue(result).build());
responseObserver.onCompleted();
} catch (Exception e) {
logger.error("onError : {}" , e.getMessage());
responseObserver.onError(new StatusRuntimeException(Status.INTERNAL.withDescription(e.getMessage())));
}
And if client sends denominator = 0 , it will get :
Exception in thread "main" io.grpc.StatusRuntimeException: INTERNAL: / by zero
Good , / by zero
is passed to client.
But the problem is , in a truly enterprise environment, there will be a lot of RuntimeException
s , and if I want to pass these exception's messages to client , I will have to try catch each method , which is very cumbersome.
Is there any global interceptor that intercepts every method , catching RuntimeException
and trigger onError
and propagate the error message to client ? So that I don't have to deal with RuntimeException
s in my server code .
Thanks a lot !
Note :
<grpc.version>1.0.1</grpc.version>
com.google.protobuf:proton:3.1.0
io.grpc:protoc-gen-grpc-java:1.0.1
Below code will catch all runtime exceptions, Also refer the link https://github.com/grpc/grpc-java/issues/1552
public class GlobalGrpcExceptionHandler implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
Metadata requestHeaders, ServerCallHandler<ReqT, RespT> next) {
ServerCall.Listener<ReqT> delegate = next.startCall(call, requestHeaders);
return new SimpleForwardingServerCallListener<ReqT>(delegate) {
@Override
public void onHalfClose() {
try {
super.onHalfClose();
} catch (Exception e) {
call.close(Status.INTERNAL
.withCause (e)
.withDescription("error message"), new Metadata());
}
}
};
}
}