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

1.x: add Completable.safeSubscribe option + RxJavaPlugins hook support #3942

Merged
merged 8 commits into from
Jun 1, 2016

Conversation

akarnokd
Copy link
Member

Add option to safely subscribe a CompletableSubscriber / regular Subscriber and handle onXXX failures.

See also: #3938

Naming and whether or not the safe wrapping should be the default is open to discussion.

@bryant1410
Copy link

In my opinion safe wrapping should be the default as it's the default in Observable and Single. At least the 3 should behave the same way. When using them, one should expect them to have a difference in their essential semantics, and not in these kind of things.


/**
* Subscribes the given CompletableSubscriber to this Completable instance
* and handles exceptions throw by its onXXX methods.

Choose a reason for hiding this comment

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

throw -> thrown

@bryant1410
Copy link

Should the tests about error handling plugin in #3938 be here? Or we leave it in that PR?

@akarnokd
Copy link
Member Author

@bryant1410 Your PR has a test failure:

rx.plugins.RxJavaPluginsTest > testOnErrorWhenUsingCompletable FAILED
    java.lang.AssertionError: expected:<java.lang.RuntimeException: test onError> but was:<null>
        at org.junit.Assert.fail(Assert.java:93)
        at org.junit.Assert.failNotEquals(Assert.java:647)
        at org.junit.Assert.assertEquals(Assert.java:128)
        at org.junit.Assert.assertEquals(Assert.java:147)
        at rx.plugins.RxJavaPluginsTest.testOnErrorWhenUsingCompletable(RxJavaPluginsTest.java:314)

@akarnokd
Copy link
Member Author

Fixed typo, renamed methods

@bryant1410
Copy link

@akarnokd They fail on purpose because I made the test but didn't fix the problem (Completable is not calling the error handling plugin).

@@ -1992,7 +2014,7 @@ public final void subscribe(CompletableSubscriber s) {
throw new NullPointerException("The RxJavaPlugins.onSubscribe returned a null Subscriber");

Choose a reason for hiding this comment

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

I think this can only happen if s is null, which is checked in requiredNonNull(s). Same in subscribe(Subscriber)

Choose a reason for hiding this comment

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

Also, why using sw? Is just an alias of s.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's there to capture plugin errors once the plugin API is extended.

Copy link

@bryant1410 bryant1410 May 14, 2016

Choose a reason for hiding this comment

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

Do you mean once there is an execution hook for Completable? Or what do you mean?

@bryant1410
Copy link

bryant1410 commented May 14, 2016

The methods should be the other way around. Following Single and Observable, there should be a single unsafeSubscribe method, which accepts a parameter of type CompletableSubscriber. And subscribe should be present in the following ways: subscribe(), subscribe(Action0), subscribe(Action1<? super Throwable>, Action0), subscribe(Subscriber) and subscribe(CompletableSubscriber).

@akarnokd
Copy link
Member Author

The subscribe() methods wrap with SafeComletableSubscriber similar to how Observable.subscribe wraps with SafeSubscriber. subscribe(Subscriber) is there to allow conversion and cross-type APIs to bypass the safety overhead.

@akarnokd
Copy link
Member Author

Updated with plugin support.

@akarnokd akarnokd changed the title 1.x: add Completable.safeSubscribe option 1.x: add Completable.safeSubscribe option + RxJavaPlugins hook support May 14, 2016
@bryant1410
Copy link

@akarnokd
Copy link
Member Author

Sure.

@akarnokd
Copy link
Member Author

Done.

@@ -52,8 +52,8 @@ public void onCompleted() {

@Override
public void onError(Throwable e) {
RxJavaPluginUtils.handleException(e);

Choose a reason for hiding this comment

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

This should be done if !done, as in SafeSubscriber.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done or not, the exception has to be reported to the handler. This also makes your test pass.

Choose a reason for hiding this comment

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

But why SafeSubscriber doesn't do this? Either this class or the other one are not behaving right.

Copy link
Member Author

Choose a reason for hiding this comment

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

Can you demonstrate that with an unit test?

Choose a reason for hiding this comment

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

Do you want me to make a unit test for the case that onError gets called twice in a SafeSubcriber and SafeCompletableSubscriber to see if the error handler gets called twice? I don't know if it's worth it. What it happens is that it just doesn't look good to me when behavior is different in Completable from Single and Observable.

@bryant1410
Copy link

The comment // TODO plugin wrapping onSubscribe in Completable#create can be deleted, as the constructor is already calling the hook now.

@@ -1843,7 +1846,7 @@ public final Completable startWith(Completable other) {
*/
public final Subscription subscribe() {
final MultipleAssignmentSubscription mad = new MultipleAssignmentSubscription();
subscribe(new CompletableSubscriber() {
unsafeSubscribe(new CompletableSubscriber() {

Choose a reason for hiding this comment

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

SafeCompletableSubscriber is not used here nor the others subscribe methods, except for subscribe(Subscriber). I think subscribe methods should call between themselves (as in Observable#subscribe methods) to refactor code and avoid forgetting this kind of things.

Choose a reason for hiding this comment

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

unsafeSubscribe should call between themselves too.

Copy link

@bryant1410 bryant1410 May 17, 2016

Choose a reason for hiding this comment

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

This should call subscribe now instead, doesn't it? And the others subscribe methods.

Copy link
Member Author

Choose a reason for hiding this comment

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

No, the rest are intermediate operators or already perform custom logic in addition to reporting the error to a plugin. Plus, this particulare use case, the subscriber is not expected to crash.

Choose a reason for hiding this comment

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

But the idea of the safe subscribe is to ensure the caller that the contract will be met. Why in this particular case it won't?

Choose a reason for hiding this comment

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

But SafeSubscriber in the first line of the javadocs says:

SafeSubscriber is a wrapper around Subscriber that ensures that the Subscriber complies with the Observable contract.

Copy link
Member Author

Choose a reason for hiding this comment

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

Right. However, this method doesn't run any user supplied code and thus no need to wrap it into a safe completable subscriber.

Choose a reason for hiding this comment

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

You're right. However, the other 2 subscribe methods that don't use SafeCompletableSubscriber should do it. To assert that the Action instances are called at most once, and not both, complying with the contract.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added the safeguard to those methods.

Choose a reason for hiding this comment

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

I see. Why not reusing SafeCompletableSubscriber?

@akarnokd
Copy link
Member Author

Removed comment, changed to reuse methods, added onStart call.

*
* @return {@link RxJavaCompletableExecutionHook} implementation to use
*/
public RxJavaCompletableExecutionHook getCompletableExecutionHook() {
Copy link
Member

Choose a reason for hiding this comment

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

@Experimental

@zsxwing
Copy link
Member

zsxwing commented Jun 1, 2016

Please add the missing @Experimental. Otherwise 👍

@akarnokd
Copy link
Member Author

akarnokd commented Jun 1, 2016

Added missing annotations

* returned as a pass through
*/
public <T> Completable.CompletableOnSubscribe onCreate(Completable.CompletableOnSubscribe f) {
Copy link
Member

Choose a reason for hiding this comment

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

Good catch!

@zsxwing zsxwing merged commit 4b61060 into ReactiveX:1.x Jun 1, 2016
@stevegury
Copy link
Member

👍

@akarnokd akarnokd deleted the CompletableSafeSubscribe branch June 28, 2016 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants