grpc-java: io.grpc.StatusRuntimeException when using shutdownNow

What version of gRPC-Java are you using?

1.26.0

What is your environment?

Mac Java 8/11

What did you expect to see?

No exception

What did you see instead?

io.grpc.StatusRuntimeException: UNAVAILABLE: Channel shutdownNow invoked
	at io.grpc.Status.asRuntimeException(Status.java:533)
	at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:449)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	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:700)
	at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39)
	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:399)
	at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:521)
	at io.grpc.internal.ClientCallImpl.access$300(ClientCallImpl.java:66)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:641)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$700(ClientCallImpl.java:529)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:703)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:692)
	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)

Steps to reproduce the bug

Note this is a BiDi stream call. The client is closing the connection on the server without the server knowing this will happen. This is done by calling:

streamObserver.onCompleted();
channel.shutdownNow();
channel.awaitTermination(maxWaitMs, TimeUnit.MILLISECONDS);

Everything seems to work properly but I see the above exception in my logs. Note: I don’t believe this is the same as #4102 as I’m calling shutdownNow() only once.

As an aside, I’d prefer to just call shutdown() instead of shutdownNow() but awaitTermination takes a very long time (10-20 seconds) if I do this. I don’t know if it’s related.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (7 by maintainers)

Most upvoted comments

I’m not a grpc developer, but I think this is intented.

On bidi streams both sides need to close explicitly. There is no built-in part in the protocol that says that if one side closes its stream the other side needs to close the stream also. You can of course do that in your implementation, as you did in TestServer StreamObserver<TestRequest> onCompleted().

You could also send a special message which signals the server that the client is finished. In other contexts this is often called “Packet of Death” or “Kiss of Death message”. NTP has this.

In your reproducer client you call newStreamObserver.onCompleted(). That’s wrong, since it is a callback when the server calls onCompleted on his side of the stream. The callback should never be called by your code directly.

Here’s a test case. Am I doing something wrong or is there a real bug here? https://github.com/Randgalt/grpc-issue-6642