Skip to content

Commit 5d4c1d9

Browse files
henry-alakazhangbenlesh
andauthoredJul 8, 2022
fix(share): Prevent setup/reset race condition in share with refCount (#7005)
* fix(shareReplay): Prevent setup/reset race condition in shareReplay with refCount * test: ensure we're awaiting the result of firstValueFrom Co-authored-by: Ben Lesh <ben@benlesh.com>
1 parent 47fa8d5 commit 5d4c1d9

File tree

2 files changed

+22
-2
lines changed

2 files changed

+22
-2
lines changed
 

‎spec/operators/shareReplay-spec.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { expect } from 'chai';
22
import * as sinon from 'sinon';
33
import { shareReplay, mergeMapTo, retry, take } from 'rxjs/operators';
44
import { TestScheduler } from 'rxjs/testing';
5-
import { Observable, Operator, Observer, of, from, defer, pipe } from 'rxjs';
5+
import { Observable, Operator, Observer, of, from, defer, pipe, combineLatest, firstValueFrom, BehaviorSubject } from 'rxjs';
66
import { observableMatcher } from '../helpers/observableMatcher';
77

88
/** @test {shareReplay} */
@@ -274,6 +274,20 @@ describe('shareReplay', () => {
274274
expect(subscriptions).to.equal(1);
275275
});
276276

277+
it('should only subscribe once each with multiple synchronous subscriptions and unsubscriptions ', async () => {
278+
// This may seem very specific, but it's a regression test for https://github.com/ReactiveX/rxjs/issues/6760
279+
280+
let subscriptions = 0;
281+
const source = defer(() => {
282+
++subscriptions;
283+
// Needs to be an observable that doesn't complete
284+
return new BehaviorSubject(1);
285+
}).pipe(shareReplay({ bufferSize: 1, refCount: true }));
286+
287+
await firstValueFrom(combineLatest([source, source]));
288+
expect(subscriptions).to.equal(1);
289+
});
290+
277291
it('should default to refCount being false', () => {
278292
testScheduler.run(({ cold, expectObservable, expectSubscriptions }) => {
279293
const source = cold('a-b-c-d-e-f-g-h-i-j');

‎src/internal/operators/share.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,13 @@ export function share<T>(options: ShareConfig<T> = {}): MonoTypeOperatorFunction
211211
// Basically, `subscriber === dest.subscribe(subscriber)` is `true`.
212212
dest.subscribe(subscriber);
213213

214-
if (!connection) {
214+
if (
215+
!connection &&
216+
// Check this shareReplay is still activate - it can be reset to 0
217+
// and be "unsubscribed" _before_ it actually subscribes.
218+
// If we were to subscribe then, it'd leak and get stuck.
219+
refCount > 0
220+
) {
215221
// We need to create a subscriber here - rather than pass an observer and
216222
// assign the returned subscription to connection - because it's possible
217223
// for reentrant subscriptions to the shared observable to occur and in

0 commit comments

Comments
 (0)
Please sign in to comment.