Hi all,
I've been experimenting with the following scenario.
Service A gets a synchronous GRPC call (handled by thread-A from the default grpc thread pool). Within that call, it calls Service B via an asynchronous call (stub). It provides a StreamObserver and expects a streamed response from Service B. The ManagedChannel to Service B has it's own executor (though the problem persists with default executor as well).
Once, the thread-A calls Service B asynchronously, it returns and finishes.
Observation:
In the moment, when thread-A
finishes, the request to Service B gets cancelled. (Status: CANCELLED, see Stacktrace below).
io.grpc.StatusRuntimeException: CANCELLED
at io.grpc.Status.asRuntimeException(Status.java:526) ~[grpc-core-1.5.0.jar:1.5.0]
at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:380) [grpc-stub-1.5.0.jar:1.5.0]
at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:419) [grpc-core-1.5.0.jar:1.5.0]
at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:60) [grpc-core-1.5.0.jar:1.5.0]
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:493) [grpc-core-1.5.0.jar:1.5.0]
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$500(ClientCallImpl.java:422) [grpc-core-1.5.0.jar:1.5.0]
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:525) [grpc-core-1.5.0.jar:1.5.0]
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) [grpc-core-1.5.0.jar:1.5.0]
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:102) [grpc-core-1.5.0.jar:1.5.0]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_40]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_40]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_40]
If I debug and put a breakpoint before thread-A returns (breakpoint that only stops thread-A), the call to Service B is successful, the streamed responses get handled correctly by threads of the executor from B's channel etc. As soon as I let thread-A finish, I run again into the exception above.
Can you think of an explanation for this?
Why can't the calling thread of an async thread not be finished? Shouldn't it be enough to pass the StreamObserver to the async call?
Looking forward to your help and happy to provide further details!