我有一个简单的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
方法。我认为程序失败了:
但令人惊讶的是(对我而言)代码运行成功,只有消息丢失。输出是:
Start
Finish
Error
由于异步性质,甚至可以在错误至少通过响应观察者传播之前调用完成。这是一种理想的行为吗?我不能丢失任何消息。我错过了什么吗?
谢谢你,Adam
答案 0 :(得分:1)
这是预期的行为。正如您所提到的,API是异步的,因此错误通常也必须是异步的。 gRPC不保证消息传递,并且在流式传输RPC故障的情况下,不指示远程端接收了哪些消息。高级ClientCall API calls this out。
如果您需要更强的保证,则必须在应用程序级别添加,例如回复或状态为OK
。例如,在gRPC + Image Upload中,我提到使用双向流进行确认。
创建ManagedChannelBuilder
没有错误,因为通道是惰性的:它只在必要时创建TCP连接(并在必要时重新连接)。此外,由于大多数故障都是暂时的,我们不希望阻止通道上所有未来的RPC,因为您的客户端恰好在网络中断时启动。
由于API已经异步,因此grpc-java可以在发送时有目的地丢弃消息,即使它知道发生了错误(即,它选择不抛出)。因此,几乎所有错误都通过onError()
传递给应用程序。