shareReplay source subscription persistence limits
0 reputation · 15 Dec 2021, 17:06 UTC
0 reputation · 15 Dec 2021, 17:06 UTC
The shareReplay operator is used to multicast a source Observable and buffer a specific number of emissions for late subscribers. A critical design consideration is how the operator manages the underlying subscription to the source when the number of active observers reaches zero.
By default, shareReplay may maintain the connection to the source indefinitely, even after all downstream observers have unsubscribed. While the refCount configuration property is available to automate unsubscription, the precise behavior regarding buffer retention and source reconnection varies based on the configuration object used.
refCount: true?When shareReplay is used with { refCount: true }, the internal replay buffer is discarded and the subscription to the source Observable is torn down as soon as the number of active observers reaches zero. A new observer arriving after this teardown causes shareReplay to resubscribe to the source and start with a fresh buffer; previously emitted values are not replayed unless they fall within a configured bufferSize or windowTime that still holds them.
shareReplay({ refCount: true }) unsubscribes from the source when observer count drops to 0.The operator treats the refCount flag as a lifecycle switch: it mirrors the source while there is at least one subscriber, and when the last subscriber leaves it performs a full teardown, which includes dropping the cached values. This prevents stale replays and avoids keeping a hot connection alive unnecessarily.
import { interval } from 'rxjs';
import { shareReplay } from 'rxjs/operators';
const source = interval(1000).pipe(
shareReplay({ bufferSize: 3, refCount: true })
);
let sub1 = source.subscribe(v => console.log('sub1:', v));
let sub2 = source.subscribe(v => console.log('sub2:', v));
// after a few seconds, unsubscribe both
setTimeout(() => {
sub1.unsubscribe();
sub2.unsubscribe();
console.log('observers: 0');
}, 5000);
// new subscription after teardown
setTimeout(() => {
source.subscribe(v => console.log('new sub:', v));
}, 12000);
Expected console output:
If you observe that the source continues to emit after all observers have left, verify whether refCount was explicitly set to false or omitted, or whether another operator is preserving the subscription.
Use comments to ask for clarification. Post a solution as an answer.
32,275 reputation · 16 Dec 2021, 03:47 UTC
The accepted answer states that shareReplay({ refCount: true }) discards the internal buffer when the observer count hits zero. That is not the behavior in RxJS 6.4+/7: the source subscription is torn down, but the replay buffer is retained. A new subscriber after teardown immediately receives the buffered emissions first, and only then does the operator resubscribe to the source.
interval), late subscribers see stale buffered values followed by the restarted sequence — easy to mistake for duplicates.bufferSize or windowTime bounds retention.windowTime, stale entries are filtered by age at subscription time, so the replayed set may shrink between subscribers.Wrap the source in defer with a subscription counter, unsubscribe all observers, resubscribe, and assert: (1) the counter increments again, (2) the first emissions equal the old buffer. Confirm against your installed version — error-caching and resubscription semantics have shifted across minor RxJS releases.