Skip to content

publish(Func1) may leave operators hang #3673

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

Closed
akarnokd opened this issue Feb 5, 2016 · 1 comment
Closed

publish(Func1) may leave operators hang #3673

akarnokd opened this issue Feb 5, 2016 · 1 comment
Labels

Comments

@akarnokd
Copy link
Member

akarnokd commented Feb 5, 2016

The following unit test fails because the sequence doesn't complete:

    public void publishConcat() {
        TestSubscriber<Integer> ts = TestSubscriber.create();

        Observable.range(1, 3)
        .publish(o -> o.take(5).concatWith(o.takeLast(5)))
        .subscribe(ts);

        ts.assertValues(1, 2, 3);
        ts.assertNoErrors();
        ts.assertCompleted();
    }

The problem lies in operator publish(). When a published source completes, the operator switches back to a ready state where more subscribers can be subscribed to it and they all receive values from the upstream on the next connect(). Otherwise, it wouldn't be possible to observe the sequence again from the beginning by more than one subscriber.

In the test, the source is sort and by the time take(5) completes and makes concat subscribe to o, the published source, the underlying OperatorPublish is already in the ready state and awaits another connect, which will never arrive, thus leaving the second takeLast hang forever.

This anomaly is there since the rewrite of publish() to support backpressure, namely when it doubles as a multicast source. Previously, a PublishSubject was the mediator between the upstream and the use places in the lambda. PublishSubject, when completed will complete any latecommer subscriber such as the one by takeLast() thus the unit test passes.

The solution would be to write a request-coordinating internal PublishSubject variant and dispatch upstream values over it in the multicast scenario.

(Note that unbounded replay has no such problem because it stays in the completed state until the next connect() call, thus latecommers still receive the orignal sequence. Because it buffers all values, there is no penalty for latecommers after a new connect() call.)

@akarnokd
Copy link
Member Author

Closing via #3681

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

No branches or pull requests

1 participant