apollo-client
apollo-client copied to clipboard
Polling stops when all sububscriptions are unsubscribed and does not restart on new subscriptions
Intended outcome:
I want to be able to configure pollInterval on a query, then pass the valueChanges observable to be used by other components. I want these components to be able to subscribe and unsubscribe like they please, and I want the polling to work while there is at least one active subscription.
Also, I want to be able to use the switchMap operator with the valueChanges observable without worrying about the polling breaking.
Actual outcome:
The query starts to poll when the first subscription is active, and it stops when all subscriptions are unsubscribed. Afterwards, the polling stays disabled and is not started again when there is a new subscription.
When I use switchMap and return valueChanges of the same query on multiple subsequent calls of the map callback, switchMap always first unsubscribes from the old observable and then subscribes on the new (= old) observable, so there is a brief moment without any active subscriptions, and the polling permanently stops.
How to reproduce the issue:
I created an interactive stackblitz
https://stackblitz.com/edit/angular-ivy-egtyv6?file=src%2Fapp%2Fapp.component.ts
If you click Subscribe, then Unsubscribe, and then Subscribe again, the polling stops working.
If you click Subscribe with switchMap , then click Emit switch map subject, the polling works. But if you click Emit switch map subject again, the polling stops working.
Versions
Can't run this command in stackblitz, but see the versions there

I'm having the same issue when the observable is on a provided-in-root service. When testing it providing the service at component level the polling is working without issues. Also, even on a singleton service, when reassigning the observable, the polling is able to continue.
luckily this is under investigation?
I've done some digging and I think I've found the cause of this.
- When all subscriptions are unsubscribed, the
tearDownQuery()is called. - It calls
stopPolling(), which setsthis.options.pollInterval = 0. - Later when you subscribe again, the
pollIntervaloption is still0, so it only does one query, but does not poll.
So the root cause of this is that this is because the original pollInterval option is lost when stopPolling is called by tearDownQuery...
How could a fix look like? To me it looks like the main issue is that every trace of poll information gets deleted after the last subscriber unsubscribed (as described by you @MiniGod). There is no chance, after subscriptions got cleared, to know someone created that query with pollInterval: x
If the initial value (and all upcoming changes to pollInterval from user-land) would be cached, the next subscriber could start to poll again, right?
What I don't know is, if there need further checks to not clear everything and set isTornDown = true
private tearDownQuery() {
if (this.isTornDown) return;
if (this.concast && this.observer) {
this.concast.removeObserver(this.observer);
delete this.concast;
delete this.observer;
}
this.stopPolling();
// stop all active GraphQL subscriptions
this.subscriptions.forEach((sub) => sub.unsubscribe());
this.subscriptions.clear();
this.queryManager.stopQuery(this.queryId);
this.observers.clear();
this.isTornDown = true;
}