Pattern for rich error handling in gRPC

前端 未结 2 727
名媛妹妹
名媛妹妹 2020-12-13 04:45

What is the pattern for sending more details about errors to the client using gRPC?

For example, suppose I have a form for registering a user, that sends a message

相关标签:
2条回答
  • 2020-12-13 04:48

    Include additional error details in the response Metadata. However, still make sure to provide a useful status code and message. In this case, you can add RegisterUserResponse to the Metadata.

    In gRPC Java, that would look like:

    Metadata.Key<RegisterUserResponse> REGISTER_USER_RESPONSE_KEY =
        ProtoUtils.keyForProto(RegisterUserResponse.getDefaultInstance());
    ...
    Metadata metadata = new Metadata();
    metadata.put(REGISTER_USER_RESPONSE_KEY, registerUserResponse);
    responseObserver.onError(
        Status.INVALID_ARGUMENT.withDescription("Email or password malformed")
          .asRuntimeException(metadata));
    

    Another option is to use the google.rpc.Status proto which includes an additional Any for details. Support is coming to each language to handle the type. In Java, it'd look like:

    // This is com.google.rpc.Status, not io.grpc.Status
    Status status = Status.newBuilder()
        .setCode(Code.INVALID_ARGUMENT.getNumber())
        .setMessage("Email or password malformed")
        .addDetails(Any.pack(registerUserResponse))
        .build();
    responseObserver.onError(StatusProto.toStatusRuntimeException(status));
    

    google.rpc.Status is cleaner in some languages as the error details can be passed around as one unit. It also makes it clear what parts of the response are error-related. On-the-wire, it still uses Metadata to pass the additional information.

    You may also be interested in error_details.proto which contains some common types of errors.

    I discussed this topic during CloudNativeCon. You can check out the slides and linked recording on YouTube.

    0 讨论(0)
  • 2020-12-13 05:02

    We have 3 different ways we could handle the errors in gRPC. For example lets assume the gRPC server does not accept values above 20 or below 2.

    1. Using gRPC status codes.

      if(number < 2 || number > 20){
           Status status = Status.FAILED_PRECONDITION.withDescription("Not between 2 and 20");
           responseObserver.onError(status.asRuntimeException());
       }
      
    2. Metadata (we can pass objects via metadata)

      if(number < 2 || number > 20){
           Metadata metadata = new Metadata();
           Metadata.Key<ErrorResponse> responseKey = ProtoUtils.keyForProto(ErrorResponse.getDefaultInstance());
           ErrorCode errorCode = number > 20 ? ErrorCode.ABOVE_20 : ErrorCode.BELOW_2;
           ErrorResponse errorResponse = ErrorResponse.newBuilder()
                   .setErrorCode(errorCode)
                   .setInput(number)
                   .build();
           // pass the error object via metadata
           metadata.put(responseKey, errorResponse);
           responseObserver.onError(Status.FAILED_PRECONDITION.asRuntimeException(metadata));
       }
      
    3. Using oneof - we can also use oneof to send error response

    oneof response {
        SuccessResponse success_response = 1;
        ErrorResponse error_response = 2;
      }
    }
    

    client side:

    switch (response.getResponseCase()){
        case SUCCESS_RESPONSE:
            System.out.println("Success Response : " + response.getSuccessResponse().getResult());
            break;
        case ERROR_RESPONSE:
            System.out.println("Error Response : " + response.getErrorResponse().getErrorCode());
            break;
    }
    

    Check here for the detailed steps - https://www.vinsguru.com/grpc-error-handling/

    0 讨论(0)
提交回复
热议问题