StreamObservers.copyWithFlowControl calls StreamObserver.onComplete twice
See original GitHub issueClient stream observer on ready handler is invoked after stream is half closed.
StreamObserver<HelloReply> resp = new ClientResponseObserver<HelloRequest, HelloReply>() {
@Override
public void onNext(HelloReply value) {
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onCompleted() {
}
@Override
public void beforeStart(ClientCallStreamObserver<HelloRequest> requestStream) {
StreamObservers.copyWithFlowControl(
ImmutableList.of(HelloRequest.newBuilder().setName(payload).build()),
requestStream);
}
};
stub.sayHello(resp);
Following error is found:
> io.grpc.StatusRuntimeException: CANCELLED: Failed to call onReady.
at io.grpc.Status.asRuntimeException(Status.java:526)
at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:419)
at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:37)
at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
at io.grpc.internal.CensusStatsModule$StatsClientInterceptor$1$1.onClose(CensusStatsModule.java:684)
at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:37)
at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23)
at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40)
at io.grpc.internal.CensusTracingModule$TracingClientInterceptor$1$1.onClose(CensusTracingModule.java:391)
at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:471)
at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:63)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:553)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$600(ClientCallImpl.java:474)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamOnReady.runInContext(ClientCallImpl.java:613)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalStateException: call already half-closed
at com.google.common.base.Preconditions.checkState(Preconditions.java:501)
at io.grpc.internal.ClientCallImpl.halfClose(ClientCallImpl.java:418)
at io.grpc.PartialForwardingClientCall.halfClose(PartialForwardingClientCall.java:43)
at io.grpc.ForwardingClientCall.halfClose(ForwardingClientCall.java:22)
at io.grpc.ForwardingClientCall$SimpleForwardingClientCall.halfClose(ForwardingClientCall.java:44)
at io.grpc.PartialForwardingClientCall.halfClose(PartialForwardingClientCall.java:43)
at io.grpc.ForwardingClientCall.halfClose(ForwardingClientCall.java:22)
at io.grpc.ForwardingClientCall$SimpleForwardingClientCall.halfClose(ForwardingClientCall.java:44)
at io.grpc.stub.ClientCalls$CallToStreamObserverAdapter.onCompleted(ClientCalls.java:330)
at io.grpc.stub.StreamObservers$1FlowControllingOnReadyHandler.run(StreamObservers.java:52)
at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onReady(ClientCalls.java:426)
at io.grpc.PartialForwardingClientCallListener.onReady(PartialForwardingClientCallListener.java:42)
at io.grpc.ForwardingClientCallListener.onReady(ForwardingClientCallListener.java:23)
at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onReady(ForwardingClientCallListener.java:40)
at io.grpc.PartialForwardingClientCallListener.onReady(PartialForwardingClientCallListener.java:42)
at io.grpc.ForwardingClientCallListener.onReady(ForwardingClientCallListener.java:23)
at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onReady(ForwardingClientCallListener.java:40)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamOnReady.runInContext(ClientCallImpl.java:608)
payload
is a string of 1 million char.
This error does not happen with small payload.
What version of gRPC are you using?
1.11.0
What did you expect to see?
onComplete()
should only be called once for request stream.
Issue Analytics
- State:
- Created 5 years ago
- Comments:8 (4 by maintainers)
Top Results From Across the Web
StreamObserver (grpc-all 1.51.0 API)
Can be called many times but is never called after onError(Throwable) or onCompleted() are called. Unary calls must invoke onNext at most once....
Read more >Can someone explain to me what's the proper usage of gRPC ...
Basically, I need too transfer error details from gRPC server to client, but I find it hard to understand the proper usage of...
Read more >grpc-java/stub/src/test/java/io/grpc/stub/ServerCallsTest.java
Is called twice, once to permit the first message and once again after the first message. // has been processed (auto flow control)....
Read more >Airframe RPC - wvlet.github.io
Airframe RPC enables calling Scala methods at remote servers. ... StreamObserver // Create an async gRPC client val client = ServiceGrpc.
Read more >Client cancellation unnoticed by server until it calls ...
Regardless, the server behaves the same: the loop executes 10 times (evidence via log messages), and during the call to streamObserver.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@biran0079 That’s certainly possible. isReady can change spuriously, and its only a hint. Consider the case where another RPC consumers the last of the flow control window between the time you get the onReadyCallback, and when you check isReady.
@carl-mastrangelo Exactly.