Rxjs: shareReplay with refCount doesn't restart due to unsubscriptions if the source completes first

Created on 26 May 2020  路  6Comments  路  Source: ReactiveX/rxjs

Bug Report

Current Behavior
shareReplay doesn't restart due to unsubscriptions when refCount is true if the source completes before the subscribers.

Reproduction

import {interval} from 'rxjs';
import {finalize, shareReplay, take} from 'rxjs/operators'

const sharedSource = interval(100).pipe(
  take(5),
  finalize(() => {
    console.log('The source has completed!')
  }),
  shareReplay({refCount: true, bufferSize: 1}),
);

const s1 = sharedSource.subscribe(x => console.log('subscription 1', x));
const s2 = sharedSource.subscribe(x => console.log('subscription 2', x));
console.log('Two active subscriptions...')

setTimeout(() => {
  s1.unsubscribe();
  s2.unsubscribe();
  console.log('Both subscriptions have been unsubscribed (refCount === 0)')
}, 550)

setTimeout(() => {
  console.log('Creating a new subscription...')
  sharedSource.subscribe(x => console.log('subscription 3', x))
}, 600)

Expected behavior
I would expect to restart the subscription to the source after the refCount has gone down to zero.

Environment

  • Runtime: Node v12.4.0,
  • RxJS version: 6.5.5

Most helpful comment

Would it be worth it to add a test that removes the current "ambiguity"?

Yes, definitely!

Is there a way to get the behavior that I was expecting by combining other lower-level operators?

Yes: multicast(() => ReplaySubject(1))

All 6 comments

What you are seeing is the expected behaviour. Once the source completes, that's it. The completion is replayed. If you don't want this behaviour, use share instead.

Hi @cartant and thanks for your quick reply.

What you are seeing is the expected behaviour. Once the source completes, that's it. The completion is replayed. If you don't want this behaviour, use share instead.

I _really_ thought that this was a bug. Please notice that in the PR that I've opened all the existing tests are passing and I also added a new one to cover this case.

One of the reasons why I thought that this was a bug is that currently there is a test for shareReplay that states:

should restart due to unsubscriptions if refCount is true

I don't understand why that shouldn't be the case if the source has completed and all the subscribers have unsubscribed. I thought that was the point of using refCount. If that's not the expected behavior perhaps would it be worth it to add a test that makes sure that once the source has completed then the refCount is ignored?

Also, I know how to create my own operator with this behavior, but is there a way that I can get this behavior using share or publishReplay... because I can't think of a way to get that.

Thanks a lot for looking into this.

I don't understand why that shouldn't be the case ...

Look at it this way: if it resubscribes to the source it is not replaying the notifications.

I do understand what you are saying, but another way to look at it could be: when using refCount: true, then if the refCount goes down to zero then it's like nothing ever happened :smile:.

I'm not saying that you are wrong. I'm just saying that's what I expected/wished and when I found a test that seemed to state that, then that lead me to think that this was a bug. I also thought that if I wanted the behavior that you are describing as the expected one, then I could use:

source.pipe(publishReplay(1), refCount())

I thought that by having the refCount option in the shareReplay operator, then we would be able to get a behavior that's closer to the share operator...

Anyways, well, if it isn't a bug then 2 questions:

  • Would it be worth it to add a test that removes the current "ambiguity"?
  • Is there a way to get the behavior that I was expecting by combining other lower-level operators? or should I write my own operator if I wanted that behavior?

Thanks!

Would it be worth it to add a test that removes the current "ambiguity"?

Yes, definitely!

Is there a way to get the behavior that I was expecting by combining other lower-level operators?

Yes: multicast(() => ReplaySubject(1))

Thanks a lot! I'm going to get some rest now and I will send a PR with that test tomorrow. Once again: thanks a lot for being so responsive and supportive!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cartant picture cartant  路  3Comments

cartant picture cartant  路  3Comments

benlesh picture benlesh  路  3Comments

benlesh picture benlesh  路  3Comments

LittleFox94 picture LittleFox94  路  3Comments