简体   繁体   English

如何在另一个线程的函数中抛出异常?

[英]How to throw an exception in a function from another thread?

I've encountered a very odd problem: Basically, I'm implementing a server streaming grpc client in java and I'm using microprofiles as library/structure.我遇到了一个非常奇怪的问题:基本上,我在 Java 中实现了一个服务器流式 grpc 客户端,并且我使用微配置文件作为库/结构。 Microprofiles has very handy interceptors when it comes to automatic retries and fallback, but it's dependent on exceptions being thrown in the intercept-annotated function, otherwise the retries aren't being triggered.当涉及到自动重试和回退时,Microprofiles 有非常方便的拦截器,但它依赖于在拦截注释函数中抛出的异常,否则不会触发重试。

For unnary grpc calls, this works just fine, it works very similarly to an ordinary REST call.对于一元 grpc 调用,这很好用,它的工作原理与普通的 REST 调用非常相似。 But when making a client to grpc server side stream, protobuf will create it's own thread and ask for a callback to handle onNext, onError and onCompleted.但是当让一个客户端到 grpc 服务器端流时,protobuf 将创建它自己的线程并请求回调来处理 onNext、onError 和 onCompleted。 So when onError is called in the stream scope, any exception thrown won't be sent back to whatever function was used to start the stream, so there's no exceptions thrown to trigger the @Retry.因此,当在流作用域中调用 onError 时,抛出的任何异常都不会被发送回用于启动流的任何函数,因此不会抛出异常来触发 @Retry。

It's not possible to change how the asynchronous stream is handled and it's not possible to change how the @Retry is being triggered.无法更改异步流的处理方式,也无法更改 @Retry 的触发方式。 Grpc is generated code, and the @Retry trigger is based on the microprofile library. grpc是生成代码,@Retry触发器基于microprofile库。

Example:例子:

  @Retry(
          retryOn = {IOException.class, TimeoutException.class, StatusRuntimeException.class},
          maxDuration = 10,
          durationUnit =  ChronoUnit.SECONDS,
          maxRetries = 1,
          delay = 10,
          delayUnit = ChronoUnit.SECONDS
  )
  public void subscribeToLocations() {
    // --> Throwing an exception here triggers the @Retry <--
    SubscribeRequest locSubscribeRequest = SubscribeRequest.newBuilder().build();
    streamObserver = grpcStreamHandler();
    grpcBlockingstub.subscribeServerStreaming(locSubscribeRequest, streamObserver); // Can't change this.
  }

  private StreamObserver<SubscribeResponse> grpcStreamHandler() {
    return new StreamObserver<SubscribeResponse>() {
      @Override
      public void onNext(SubscribeResponse value) {
        // Handle grpc response
      }

      @Override
      public void onError(Throwable t) {
        // --> ERROR: Here, it should trigger the @Retry somehow. <--
      }

      @Override
      public void onCompleted() {
        // Handle oncomplete
      }
    };
  }

I've tried to find a solution to this for longer than I wish to admit, but still I'm at a loss.我试图找到解决方案的时间比我想承认的要长,但我仍然不知所措。 Is there a way to throw an exception in one scope which ends up in another?有没有办法在一个范围内抛出异常而在另一个范围内结束? Is there some other solution?还有其他解决方案吗?

You mix sync and async operations here, so you need to clearly define what is "success" for you and you don't need a retry raised.您在这里混合使用同步和异步操作,因此您需要清楚地定义什么是“成功”,并且不需要引发重试。 It can depend on your logic, few options with streaming:这可能取决于您的逻辑,流媒体的几个选项:

  • At least one update to onNext received, then completion or error至少收到一个 onNext 更新,然后完成或出错
  • onCompleted received with or without any updates onCompleted 收到有或没有任何更新
  • etc等等

Once you define the "success" rule, you can wrap subscription into Future and wait for it to be resolved with provided timeout.定义“成功”规则后,您可以将订阅包装到 Future 中并等待它在提供的超时时间内得到解决。 If not resolved, then throw Exception from original invocation.如果未解决,则从原始调用中抛出异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM