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

SwitchAll / SwitchLatest are broken #302

Closed
jinroh opened this issue Sep 12, 2015 · 13 comments
Closed

SwitchAll / SwitchLatest are broken #302

jinroh opened this issue Sep 12, 2015 · 13 comments
Assignees
Labels
bug Confirmed bug

Comments

@jinroh
Copy link
Contributor

jinroh commented Sep 12, 2015

switch operators do not seem to unsubscribe properly their inner subscriptions.

Here is a small repro code:

Observable.interval(1000)
  .switchLatest(function(i) {
    return Observable.interval(100).do(function(j) { console.log(i + "_" + j); });
  })
  .subscribe(function() {
  });
@benlesh
Copy link
Member

benlesh commented Sep 15, 2015

Thank you for pointing this out. Looking into this and expanding tests uncovered a variety of anomalies. I've been heads down refactoring code in this area.

@benlesh benlesh self-assigned this Sep 15, 2015
@benlesh benlesh added the bug Confirmed bug label Sep 15, 2015
@benlesh benlesh mentioned this issue Sep 15, 2015
@benlesh
Copy link
Member

benlesh commented Sep 16, 2015

@jinroh ... can you please checkout #317 and see if it solves your issues? I suspect it will. I was able to confirm your issue and write tests around it.

@jinroh
Copy link
Contributor Author

jinroh commented Sep 16, 2015

I think it solves one of the problem.
Here the example code I use:

var Rx = require("./cjs/Rx");

var Observable = Rx.Observable;

Observable.interval(1000).switchLatest(function(i) {
  return Observable.interval(100).map(function(j) {
    console.log("inner", i + "_" + j);
    return i + "_" + j;
  });
}).subscribe(function(v) {
  console.log("outer", v);
});

Outer subscription behaves as expected now:

outer 0_0
outer 0_1
outer 0_2
outer 0_3
outer 0_4
outer 0_5
outer 0_6
outer 0_7
outer 0_8
outer 1_0
outer 1_1
outer 1_2
outer 1_3
...

However, the inner subscriptions (from the map operator in my example) do not seem to be cleaned up. The "inner interval" side effects are still present. It looks like the subscription graph is not entirely disposed as it should be, causing a leak:

inner 0_0
inner 0_1
inner 0_2
inner 0_3
inner 0_4
inner 0_5
inner 0_6
inner 0_7
inner 0_8
inner 0_9
inner 1_0
inner 0_10
inner 1_1
inner 0_11
inner 1_2
inner 0_12
inner 1_3
inner 0_13
...

Not sure if this problem is linked to the Switch.. operator or more general. In my tests, this is the only operator I've used that internally unsubscribe inner-subs.

@benlesh
Copy link
Member

benlesh commented Sep 16, 2015

Returning subscriptions from the project function in the operator doesn't do anything special. They're not being cleaned up because you're creating new subscriptions and never unsubscribing therm. I'm actually amazed that worked at all. I'll check that out.

@jinroh
Copy link
Contributor Author

jinroh commented Sep 16, 2015

Thanks !

They're not being cleaned up because you're creating new subscriptions and never unsubscribing therm.

I'm not sure I understand correctly your comment. switchLatest is similar to flatMapLatest right ? Shouldn't this operator unsubscribe inner-subscriptions on its own, with a concurrency of one ?

@trxcllnt
Copy link
Member

@Blesh the project function in this example isn't returning a Subscription, the outer subscribe call is just indented a bit.

@jinroh
Copy link
Contributor Author

jinroh commented Sep 16, 2015

@trxcllnt oh i see what @Blesh said now !
edited my comment to remove the ident.

@benlesh
Copy link
Member

benlesh commented Sep 16, 2015

Sorry, I was looking at it from my phone before. Looked like it was all together on that little screen

@benlesh
Copy link
Member

benlesh commented Sep 16, 2015

I see the problem... PR incoming

@jinroh
Copy link
Contributor Author

jinroh commented Sep 16, 2015

(me thinking out loud)
I find this bug quite interesting because it shows that the marble tests, as I understand them, cannot validate the correction of these kind of issues (not that the previous tests forms could, but still...).

Could be interesting to find out how to simply test the unsubscription on inner side-effects...

@benlesh
Copy link
Member

benlesh commented Sep 16, 2015

@jinroh this will require just a regular synchronous test.

@mattpodwysocki
Copy link
Collaborator

@jinroh you're absolutely right, marble diagrams will not fix this issue and I have said from the beginning that we need a hybrid approach with concrete numbers. For example, in RxJS the current version, we not only track the results, but also the subscriptions, which is not something the current implementation does. For example, with case, we have to track the subscription of all the inners

@benlesh
Copy link
Member

benlesh commented Sep 17, 2015

Marble diagrams are amazing/perfect for verifying sequences of notifications.

What we need to add are the output of additional events that occur during the execution of the observable. Mostly just timings of inner subscriptions and unsubscriptions.

@lock lock bot locked as resolved and limited conversation to collaborators Jun 7, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Confirmed bug
Projects
None yet
Development

No branches or pull requests

4 participants