如果没有服务器

时间:2016-05-30 07:13:05

标签: client grpc

我有一个简单的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 call
  • 或observer.onNext

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

谢谢你,Adam

1 个答案:

答案 0 :(得分:1)

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

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

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

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