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

Fix to future cancellation #1267

Closed

Conversation

mattrjacobs
Copy link
Contributor

Right now, Observable.from(Future f) emits onError(CancellationException) when f starts out in a cancelled state. This change makes Observable.from(f) emit nothing at all.

1) Creating an Observable from an already-cancelled Future should emit nothing (equivalent to Observable.never())
   (it currently emits onError(CancellationException)
2) Creating an Observable from a Future then unsubscribeing immediately before Future.get()
   unblocks should be an Observable.never().  This test already passes.
@headinthebox
Copy link
Contributor

Mmm, not sure if that is better. I think it makes more sense to call onError in that case. Why do you think being silent is better?

@cloudbees-pull-request-builder

RxJava-pull-requests #1161 SUCCESS
This pull request looks good

@mattrjacobs
Copy link
Contributor Author

My understanding of the Rx contract was that an outer unsubscribe should cause downstream emissions to stop whenever possible.

I encountered a case where Observable.zip(Observable.empty(), Observable.from(future), func) was emitting onError(CancellationException). Zip loops through the Observables and, on the onCompleted from the first Observable, unsubscribed from the 2nd Observable (thereby cancelling the underlying future). The onError then gets propagated out of the zip.

@headinthebox
Copy link
Contributor

I think the question is more about the semantics of zip than of from(Future). Zip should stop whenever one of the sources completes. I must admit that the error behavior is underspecified.

In .NET (pseudo notation where ] is successful termination and > error) zipping one sequence that terminates normally with a sequence that terminates with an error will wait until the second sequence produces the next value before terminating:

  [1].zip([1,      >, (x,y) => (x,y))
=
 [(1,1),     >

whereas (using 18.3, for samples I stick to the released version, may be changed in master since there were a lot of changes to zip) this returns [(1,1)]. In 18.3 when you delay successful completion, zip waits for the successful termination before terminating:

  [1          ].zip([1,>, (x,y) => (x,y))
=
 [(1,1),    ]

So there is definitively a difference here, but in any case I'd separate that from from.

@abersnaze
Copy link
Contributor

The CancelationException is not a real error. Its more of an onComplete because it is the only way the get() can stop without returning data.

@mattrjacobs
Copy link
Contributor Author

I agree with @abersnaze. I don't find it intuitive that calling Observable.from on f (below) could ever emit onError.

Future<Integer> f = new FutureTask<Integer>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return 3;
            }
        });

@@ -62,6 +62,10 @@ public void call() {
}
}));
try {
//don't block or propagate CancellationException if already unsubscribed
if (subscriber.isUnsubscribed()) {
Copy link
Member

Choose a reason for hiding this comment

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

Agreed on this statement.

The catch could still result in an exception being thrown and unsubscribe having happened because it is a race. So we likely need a check inside the catch as well.

@benjchristensen
Copy link
Member

An onError should never occur as a result of unsubscribe being called on an Observable.

@cloudbees-pull-request-builder

RxJava-pull-requests #1177 SUCCESS
This pull request looks good

@benjchristensen
Copy link
Member

Can you please rebase this so it can be merged? It conflicts now.

@benjchristensen
Copy link
Member

Done in #1291

@mattrjacobs mattrjacobs deleted the fix-to-future-cancellation branch January 8, 2015 06:12
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

Successfully merging this pull request may close these issues.

5 participants