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

2.13 refinement/explanation #328

Closed
anthonyvdotbe opened this issue Apr 16, 2016 · 10 comments
Closed

2.13 refinement/explanation #328

anthonyvdotbe opened this issue Apr 16, 2016 · 10 comments
Assignees
Milestone

Comments

@anthonyvdotbe
Copy link
Contributor

§2.13 says:

[...] the caller MUST raise this error condition in a fashion that is adequate for the runtime environment.

I've asked about this, and @viktorklang replied saying:

[...] instead of rethrowing the exception it should use whatever mechanisms provided to it, this may include things like logging.

This reply contains a vital point which I didn't get from reading the rule, namely that the caller should not rethrow the exception. To make this clear, I propose to add an additional phrase for this to the rule:

[...] the caller MUST guarantee violating exceptions are not propagated further up the call stack and MUST raise this error condition in a fashion that is adequate for the runtime environment.

@viktorklang
Copy link
Contributor

We need to avoid having negative rules, and instead focus on speccing the only compliant behavior.

Citing the full rule here:

Calling onSubscribe, onNext, onError or onComplete MUST return normally except when any provided parameter is null in which case it MUST throw a java.lang.NullPointerException to the caller, for all other situations the only legal way for a Subscriber to signal failure is by cancelling its Subscription. In the case that this rule is violated, any associated Subscription to the Subscriber MUST be considered as cancelled, and the caller MUST raise this error condition in a fashion that is adequate for the runtime environment.

In the last sentence caller is a Publisher and there would be nowhere for that Publisher to re-throw the exception to. Since It would either run async and would only be able to throw to the thread pool which runs it, or sync, in which case it would be in subscribe and that is governed by:

1.9: Publisher.subscribe MUST call onSubscribe on the provided Subscriber prior to any other signals to that Subscriber and MUST return normally, except when the provided Subscriber is null in which case it MUST throw a java.lang.NullPointerException to the caller, for all other situations [1] the only legal way to signal failure (or reject the Subscriber) is by calling onError (after calling onSubscribe).

Do you think adding a footnote for adequate for the runtime environment explain "eg. log"?

@anthonyvdotbe
Copy link
Contributor Author

I'm probably missing something, but why can't a Publisher just ignore the exception and let it bubble up the call stack (except for the case where this occurs inside subscribe, which is indeed forbidden by §1.9)? Maybe this is actually adequate behavior for a runtime environment in which the thread pool handles any exceptions itself?

@viktorklang
Copy link
Contributor

@anthonyvdotbe If you think about it: which capacity is the Thread which runs the Publisher equipped to handle the failures of the Subscriber (which could "run" on some other machine)?

@anthonyvdotbe
Copy link
Contributor Author

@viktorklang couldn't the Publisher rely on e.g. ThreadPoolExecutor::afterExecute, or the Thread's UncaughtExceptionHandler?

@viktorklang
Copy link
Contributor

@anthonyvdotbe How would that know what to do with it, and how would the Publisher recover if it blows its own stack?

@anthonyvdotbe
Copy link
Contributor Author

I believe this:

how would the Publisher recover if it blows its own stack?

is what I'd been missing all along. So am I correct in saying the caller MUST be able to recover from violations of rule 2.13? If so, I fully get it & would like rule 2.13 to end as:

[...] and the caller MUST be able to recover from this error condition, and MUST raise it in a fashion that is adequate for the runtime environment (e.g. log).

Either way, thanks for your help @viktorklang

@viktorklang
Copy link
Contributor

@anthonyvdotbe I'm not sure that solves your problem, it only shifts it to the definition of "be able to recover".

See it like this: The rule is about what the Publisher should do if the Subscriber violates the spec. Technically the spec could omit that, but for the sake of resilience, we don't want those exceptions to propagate, because imagine a "pipeline" of 1 publisher + 1 processor + 1 processor + 1 subscriber where each of these live in different JVMs, since there is no exception backchannel, only a demand backchannel, there's no way to propagate the exception "backwards" in the chain, which means that the exceptions need to be dealt with locally. This is why non-fatal exceptions are not allowed to be thrown (except for the rules which state otherwise).

I'd like to make these kinds of things (the rationale for each of the rules) as transparent as possible, and I regrettably still haven't had time to sit down and for each rule write a rationale so that the "casual reader" can gain a deeper understanding of why the rules are as they are.

@anthonyvdotbe
Copy link
Contributor Author

Thanks @viktorklang, I'm starting to get it.

Yes, being a casual reader myself, it would definitely be helpful to have these rationales & insights (e.g. the fact that different components of a pipeline might run in different JVMs) available along with the specification. I learned about reactive streams by looking into Java 9's Flow API, and I'd guess the number of casual readers will grow substantially once Java 9 is released.

@viktorklang
Copy link
Contributor

@anthonyvdotbe Perhaps this summer, during my vacation, I'll find some time to distill these things :)

@viktorklang
Copy link
Contributor

Apologies for the delay here, fixed in #339

@viktorklang viktorklang self-assigned this Mar 5, 2017
@viktorklang viktorklang added this to the 1.0.1 milestone Mar 5, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants