there should be 1 source of truth regarding whether a call is cancelled
See original GitHub issueWhat version of gRPC-Java are you using?
1.39.0
What is your environment?
openJdk-11, ubuntu
What did you expect to see?
StatusRuntimeException
should be thrown consistently by responseObserver.onNext(...)
if responseObserver.isCancelled() == true
What did you see instead?
unless a server dispatches work to other threads, an exception is not thrown by responseObserver.onNext(...)
regardless of responseObserver.isCancelled() == true
.
This is due to the fact that there are 2 competing sources on whether a call was cancelled:
responseObserver.isCancelled()
calls call.isCancelled()- responseObserver has its own additional cancelled flag that is checked by onNext(…). This flag is set by listener.onCancel() and as listener can be called by at most 1 thread concurrently, the flag is not set until a user method exits.
It seems that observer’s additional cancelled
flag does not bring any value and is completely redundant: I think it should be removed and instead responseObserver.onNext()
should be checking cancellation status directly by call.isCancelled()
the same way responseObserver.isCancelled()
does.
Steps to reproduce the bug
see https://groups.google.com/g/grpc-io/c/4g9XpeqNngE/m/T_ZqBlWeAQAJ
Issue Analytics
- State:
- Created 2 years ago
- Comments:12 (12 by maintainers)
Top GitHub Comments
In those cases, use Context.addListener().
I will note that your code only looks so clean in dealing with the exception because it isn’t observing outbound flow control. To do that you’d need to actually be async to receive the
onReady()
callback. Not to say flow control actually benefits your code; if you have small CPU-intensive responses it doesn’t do much. My point is just that the situation is more specific than it may appear.I really wish we had a blocking streaming API to make this sort of thing easier.
Yeah, I assumed as much. I just called that out because you argued in part that the exception wasn’t matching the value of
isCancelled()
. That can be argued from an API-only perspective or from a pragmatic perspective. I was mostly arguing that it doesn’t matter too much to me from a legalese standpoint, as no code should really notice the disagreement and it is easy to workaround. It seemed you were caring about this pragmatically, so it was more “let’s not get sidetracked on the legalistic argument.”(Other APIs I would care more about the legalistic argument. But this particular one is quite old and an API wart to begin with.)
Totally agree that onCancelHandler takes plumbing. For your code organization approach I’d probably set a no-op Runnable as the onCancelHandler to disable the exception and then check
isCancelled()
as part of the loop. That’s about as much boilerplate as dealing with the exception. Today you wouldn’t need the no-op Runnable; after your suggested change you would.The main reason I’d want to cause onNext() to throw sooner is so that code that didn’t think about cancellation would abort. The runtime exception has its own problems, but I imagine many times it is worked out early in testing/deployment.