微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

处理 gRPC 中的异常

如何解决处理 gRPC 中的异常

我在让我的 gRPC 端点按预期工作时遇到了一些问题,我已经简化了我的代码来说明我遇到的问题。本质上,我无法让 exceptionally 主体中的代码执行,我不知道为什么,它似乎总是返回带有代码 UNKNowN 的状态,但我期待它返回INVALID_ARGUMENT 因为这就是我在 GetNamesService 类中的内容。异常子句中的 System.out.println 也不打印。

public class GrpcService extends GrpcServiceImplBase {

  private final GetNamesService getNamesService;

  public GrpcService(GetNamesService getNamesService) {
    this.getNamesService = getNamesService;
  }

  @Override
  public void getNames(NameRequest request,StreamObserver<NameResponse> responSEObserver) {
    getNamesService.getNames(request)
       .thenAccept(r -> {
          responSEObserver.onNext(r);
          responSEObserver.onCompleted();
       })
       .exceptionally(t -> {
          System.out.println("About to handle the exception");
          responSEObserver.onError(handleException(t));
       });
  }

  private StatusRuntimeException handleException(Throwable t) {
    if (t instanceof CompletionException) {
      return handleException(t.getCause());
    }

    if (t instanceof StatusRuntimeException) {
      var statusException = (StatusRuntimeException) t;
      return statusException;
    }

    return Status.UNKNowN.withDescription(t.getMessage()).asRuntimeException();
  }
}

public class GetNamesService {

  public CompletionStage<NameResponse> getNames(NameRequest request) {
    
    // Just throwing an exception to try and get error handling to work
    throw Status.INVALID_ARGUMENT
        .withDescription("Invalid request")
        .asRuntimeException();
  }

}

解决方法

在这块流畅的代码中:

getNamesService.getNames(request)
   .thenAccept(r -> {
      responseObserver.onNext(r);
      responseObserver.onCompleted();
   })
   .exceptionally(t -> {
      System.out.println("About to handle the exception");
      responseObserver.onError(handleException(t));
   });

如果整个块都运行,则调用 getNamesService.getNames(request),并且该方法的返回值是一个包含 thenAccept 方法的对象。然后调用该方法,并返回一个包含 exceptionally 方法的对象。最后,调用 exceptionally 方法。

这里没有魔法。这只是普通的旧 Python。该链之所以有效,是因为每个方法调用都会返回一个对象,该对象包含一个方法,使得链中的下一个方法调用有效。如果链中的方法抛出异常而不是返回包含链中下一个方法的对象,则不会执行链的其余部分。

当调用 getNamesService.getNames(request) 并抛出异常时,链中剩余的方法 thenAcceptexceptionally 不会被执行,因此没有理由期望 {{块中的 1}} 将被调用。

对于您提供的代码,System.out.println 总是抛出异常,因此上面复杂的代码块在功能上等同于:

getNamesService.getNames(request)
,

问题是您正在混合调用约定。 getNames() 返回一个 CompletionStage,因此调用代码处理它正在使用的期货,但随后会引发异常。

如果您将 GetNamesService.getNames() 的实现更改为使未来失败而不是抛出,那么它应该可以解决问题:

  public CompletionStage<NameResponse> getNames(NameRequest request) {
    // Just failing the future to try and get error handling to work
    CompletableFuture<NameResponse> f = new CompletableFuture<>();
    f.completeExceptionally(Status.INVALID_ARGUMENT
        .withDescription("Invalid request")
        .asRuntimeException());
    return f;
  }

或者,您可以在 GrpcService.getNames() 中捕获异常。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。