【问题标题】:GRPC client onNext does not fail if there is no server如果没有服务器,GRPC 客户端 onNext 不会失败
【发布时间】:2016-09-27 22:17:59
【问题描述】:

我有一个简单的 gRPC 客户端如下:

  /**
    * Client that calls gRPC.
    */
  public class Client {

  private static final Context.Key<String> URI_CONTEXT_KEY = 
      Context.key(Constants.URI_HEADER_KEY);

  private final ManagedChannel channel;
  private final DoloresRPCStub asyncStub;

  /** 
   * Construct client for accessing gRPC server at {@code host:port}. 
   * @param host 
   * @param port 
   */
  public Client(String host, int port) {
    this(ManagedChannelBuilder.forAddress(host, port).usePlaintext(true));
  }

  /** 
   * Construct client for accessing gRPC server using the existing channel. 
   * @param channelBuilder {@link ManagedChannelBuilder} instance 
   */
  public Client(ManagedChannelBuilder<?> channelBuilder) {
    channel = channelBuilder.build();
    asyncStub = DoloresRPCGrpc.newStub(channel);
  }

  /**
   * Closes the client
   * @throws InterruptedException
   */
  public void shutdown() throws InterruptedException {
    channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
  }

  /**
   * Main async method for communication between client and server
   * @param responseObserver user's {@link StreamObserver} implementation to handle 
   *        responses received from the server.
   * @return {@link StreamObserver} instance to provide requests into
   */
  public StreamObserver<Request> downloading(StreamObserver<Response> responseObserver) {
    return asyncStub.downloading(responseObserver);
  }

  public static void main(String[] args) {
    Client cl = new Client("localhost", 8999); // fail??
    StreamObserver<Request> requester = cl.downloading(new StreamObserver<Response>() {
      @Override
      public void onNext(Response value) {
        System.out.println("On Next");
      }
      @Override
      public void onError(Throwable t) {
        System.out.println("Error");
      }
      @Override
      public void onCompleted() {
        System.out.println("Completed");
      }
    }); // fail ??
    System.out.println("Start");
    requester.onNext(Request.newBuilder().setUrl("http://my-url").build()); // fail?
    requester.onNext(Request.newBuilder().setUrl("http://my-url").build());
    requester.onNext(Request.newBuilder().setUrl("http://my-url").build());
    requester.onNext(Request.newBuilder().setUrl("http://my-url").build());
    System.out.println("Finish");
  }
}

我没有启动任何服务器并运行main 方法。我想该程序在以下情况下失败:

  • 客户端创建
  • client.downloading 调用
  • 或observer.onNext

但令人惊讶的是(对我来说),代码运行成功,只有消息丢失了。输出是: Start Finish Error 由于异步特性,即使在错误至少通过响应观察者传播之前,也可以调用完成。这是理想的行为吗?我不能丢失任何消息。我错过了什么吗?

谢谢你,亚当

【问题讨论】:

    标签: client grpc


    【解决方案1】:

    这是预期的行为。正如您提到的 API 是异步的,因此错误通常也必须是异步的。 gRPC 不保证消息传递,并且在流式 RPC 失败的情况下,不指示远程端收到了哪些消息。高级 ClientCall API calls this out

    如果您需要更强的保证,则必须在应用程序级别添加,例如回复或状态为OK。例如,在gRPC + Image Upload 中,我提到了使用双向流进行确认。

    创建ManagedChannelBuilder 不会出错,因为通道是惰性的:它只在必要时创建 TCP 连接(并在必要时重新连接)。此外,由于大多数故障都是暂时的,我们不希望仅仅因为您的客户端恰好在网络中断时启动而阻止通道上的所有未来 RPC。

    由于 API 已经是异步的,grpc-java 可以在发送时故意丢弃消息,即使它知道发生了错误(即,它选择不抛出)。因此几乎所有的错误都会通过onError()传递给应用程序。

    【讨论】:

      猜你喜欢
      • 2019-07-20
      • 1970-01-01
      • 2021-06-02
      • 1970-01-01
      • 2016-01-27
      • 2020-09-09
      • 2021-01-05
      • 2018-04-12
      • 2021-04-10
      相关资源
      最近更新 更多