How to add global exception interceptor in gRPC server?

smallufo picture smallufo · Sep 30, 2016 · Viewed 13.1k times · Source

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 RuntimeExceptions , 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 RuntimeExceptions 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

Answer

mahesh picture mahesh · May 30, 2018

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());
            }
         }
      };
   }
}