Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stub: Redefine exception handling for StreamObserver #7172

Closed
wants to merge 5 commits into from

Conversation

ejona86
Copy link
Member

@ejona86 ejona86 commented Jun 30, 2020

This aligns the documentation with our recommendations expressed elsewhere
("don't throw"). Exceptions are possible, but having a try-catch around each
onNext() would be an anti-pattern for user code as it would be guaranteed to be
buggy. We would much rather have higher-level exception handling, covering many
application statements, call onError() if any of them throw an exception
because the application should generally cancel independent of the source of
the exception.

This aligns the documentation with our recommendations expressed elsewhere
("don't throw"). Exceptions are possible, but having a try-catch around each
onNext() would be an anti-pattern for user code as it would be guaranteed to be
buggy. We would much rather have higher-level exception handling, covering many
application statements, call onError() if any of them throw an exception
because the application should generally cancel independent of the source of
the exception.
* an exception, generally independent of the source, to avoid leaks. gRPC will call {@code
* onError()} when an application's implementation throws.
*
* <p>As an exception to the rule and for historical reasons, on server-side, {@code onNext()} may
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here {@code onNext()} is about the response stream observer, and {@code onCompleted()} at the end of this sentence is about the request stream observer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I realize that is wrong. It is unconditional. Fixed, which side-steps the confusing language.

Copy link
Member

@dapengzhang0 dapengzhang0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@jdcormie jdcormie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM Thanks for these clarifications!

* <p>If an exception is thrown by an implementation the caller is expected to terminate the
* stream by calling {@link #onError(Throwable)} with the caught exception prior to
* propagating it.
* <p>Although implementations are expected to not throw exceptions, if an exception occurs the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you avoid the passive voice and just say "implementations should not throw" (here and in 3 other places)?

* caller is encouraged to call {@link #onError} as part of normal application exception handling.
* That is to say, {@code onError} should be called if any related part of the application throws
* an exception, generally independent of the source, to avoid leaks. gRPC will call {@code
* onError()} when an application's implementation throws.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is helpful but perhaps it should go in the javadoc for the whole interface since it isn't specific to onNext? You could say:

Owners of a StreamObserver are responsible for eventually calling either onError() or onCompleted() to ensure that resources associated with the stream (memory, file descriptors, etc) are released.

*
* <p>As an exception to the rule and for historical reasons, on server-side, {@code onNext()} may
* throw with a {@code StatusRuntimeException} if the call is cancelled. This was necessary
* because there was not a callback available to notify the service. Services are encouraged to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider omitting "This was necessary because ... " since teaching callers the actual historical reason doesn't seem worth the extra reading

* allowed.
* <p>May only be called once and if called it must be the last method called. Although
* implementations are expected to not throw exceptions, if an exception is thrown by {@code
* onError()} further calls to the observer should be avoided.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saying "further calls should be avoided" sounds a bit odd/redundant to me coming immediately after "must be the last method called" (same for onCompleted())

* stream by calling {@link #onError(Throwable)} with the caught exception prior to
* propagating it.
* <p>Although implementations are expected to not throw exceptions, if an exception occurs the
* caller is encouraged to call {@link #onError} as part of normal application exception handling.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like a subtle change to the contract, specifically that callers are no longer expected to necessarily pass the caught exception itself to onError?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants