-
Notifications
You must be signed in to change notification settings - Fork 7.6k
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
Subscriber linking up for unsubscriptions #830
Comments
Yep it was certainly broken. Fixed in #833. Thanks for the report. |
This unit test proved the issue and is now passing: public void testMultiTake() {
final AtomicInteger count = new AtomicInteger();
Observable.create(new OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> s) {
for (int i = 0; !s.isUnsubscribed(); i++) {
System.out.println("Emit: " + i);
count.incrementAndGet();
s.onNext(i);
}
}
}).take(100).take(1).toBlockingObservable().forEach(new Action1<Integer>() {
@Override
public void call(Integer t1) {
System.out.println("Receive: " + t1);
}
});
assertEquals(1, count.get());
} |
What about OperatorMap? |
What about public Subscriber<? super T> call(final Subscriber<? super R> o) {
return new Subscriber<T>(o) { |
Consider this (running on head as of now): public static void main(String[] args) throws Exception {
AtomicInteger count = new AtomicInteger();
Observable.from(1, 2)
.map(v -> v * 2).take(1)
.subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer t) {
add(Schedulers.newThread().schedule(
i -> count.incrementAndGet(), 500, TimeUnit.MILLISECONDS
));
}
});
Thread.sleep(1000);
System.out.println(count);
} It prints 0 for me, because once take unsubscribes from map, map (or take?) propagates that unsubscription downwards as well, disrupting the delayed schedule. |
Yes, that's how it behaves, but not because
Thus, adding the (FYI that I won't be responding to this further tonight. It's past midnight and my brain is done.) |
Surprisingly, this works: Observable.from(1).take(1).delay(v -> Observable.timer(500, TimeUnit.MILLISECONDS)).subscribe(s); even if delay clearly violates the guideline above as take will call unsubscribe before delay even emits its value. It seems delay works only because its CompositeSubscription is disconnected from upstream so SafeSubscriber can't unsubscribe it before the actions were taken. So if I rewrite delay, pending onNexts won't get run because SafeSubscriber between the two will cancel the schedule/subscriptions. I think SafeSubscriber shouldn't force its actual subscriber (which is downstream) to unsubscribe. |
It doesn't violate the guideline,
It's not surprising since The only remaining oddity now that we have During the
If this were to be changed that would mean our current interpretation and implementation of guideline 4.3 is wrong. As per the current interpretation the "actual subscriber" is not downstream. The Observable.from(1).take(1).delay(v -> Observable.timer(500, TimeUnit.MILLISECONDS)).subscribe(s); The final If Considering this interpretation of guideline 4.3, what code changes would you make? @headinthebox Your input would be valuable to correct any misunderstandings or wrong implementations of the guidelines we have. The particular line of the guideline that influenced this implementation is:
Specifically we have interpreted that to mean when |
Thanks. From implementation perspective, I have two concerns:
Most likely both situation can be bypassed via |
If an operator needs to decouple from this (such as The
Sure you can, within the lifecycle of that In short, the |
If I understand correctly, a Subscriber should send unsubscriptions only upwards but never downwards. So whenever
lift
is used one would need to chain up Subscribers like this:Here,
o
comes from the client. Calling o.unsubscribe will propagate to u.unsubscribe and up on the chain. However, if u.unsubscribe is called, It won't affect o's subscriptions, i.e., u should send out onCompleted event to affect downstream.However, the
OperatorMap
doesn't do this but basically shares the same CompositeSubscription between o and u, therefore, unsubscription will affect both upstream and downstream.OperatorTake
completely ignores unsubscription coming fromo
as well, letting the following example spin trough the 1G values in the background.The text was updated successfully, but these errors were encountered: