Skip to content

Commit 9d7185b

Browse files
committed
Attempt to fix doc despose try 2
1 parent 4384b29 commit 9d7185b

3 files changed

Lines changed: 23 additions & 33 deletions

File tree

.github/workflows/e2e-tests.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ permissions: {}
33

44
on:
55
pull_request:
6-
branches:
7-
- "e2e/**"
86
merge_group:
97
workflow_dispatch:
108
schedule:

src/SIL.XForge.Scripture/ClientApp/src/xforge-common/models/realtime-doc.ts

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ export abstract class RealtimeDoc<T = any, Ops = any, P = any> {
8080
private subscribeQueryCount: number = 0;
8181
private loadOfflineDataPromise?: Promise<void>;
8282

83-
/** Indicates whether the document is in the process of being disposed. It completes when disposing is finished.*/
84-
private readonly isDisposing$ = new BehaviorSubject<boolean>(false);
8583
docSubscriptions = new Set<DocSubscription>();
8684

8785
constructor(
@@ -141,26 +139,6 @@ export abstract class RealtimeDoc<T = any, Ops = any, P = any> {
141139
return this._delete$;
142140
}
143141

144-
/**
145-
* Indicates whether the document is in the process of being disposed. This is important because when a document is
146-
* being disposed, it will still be in some places where it is expected (e.g. in the RealtimeService's docs list), but
147-
* subscribing to it would not work as expected.
148-
*/
149-
get isDisposing(): boolean {
150-
return this.isDisposing$.getValue();
151-
}
152-
153-
/**
154-
* A promise that resolves when the document is fully disposed. See `isDisposing`. When getting a realtime document
155-
* from the RealtimeService, this promise can be used to wait for the document to be fully disposed before proceeding,
156-
* rather than returning a document that is in the process of being disposed.
157-
*/
158-
get disposeCompleted(): Promise<void> {
159-
return new Promise<void>((resolve, reject) => {
160-
this.isDisposing$.subscribe({ complete: resolve, error: reject });
161-
});
162-
}
163-
164142
/**
165143
* Returns an observable that emits whenever any remote changes occur.
166144
*
@@ -245,16 +223,16 @@ export abstract class RealtimeDoc<T = any, Ops = any, P = any> {
245223
* @returns {Promise<void>} Resolves when the data has been successfully disposed.
246224
*/
247225
async dispose(): Promise<void> {
248-
this.isDisposing$.next(true);
249-
await this.realtimeService.onLocalDocDispose(this);
226+
this.realtimeService.onDocDisposeStarted(this);
250227
if (this.subscribePromise != null) {
251228
await this.subscribePromise;
252229
}
253230
this.updateOfflineDataSub.unsubscribe();
254231
this.onDeleteSub.unsubscribe();
255232
await this.adapter.destroy();
256233
this.subscribedState = false;
257-
this.isDisposing$.complete();
234+
await this.realtimeService.onLocalDocDispose(this);
235+
this.realtimeService.onDocDisposeFinished(this);
258236
}
259237

260238
addSubscriber(docSubscription: DocSubscription): void {
@@ -267,7 +245,6 @@ export abstract class RealtimeDoc<T = any, Ops = any, P = any> {
267245

268246
if (this.activeDocSubscriptionsCount === 0) {
269247
console.log(`No active subscribers for ${this.collection}:${this.id}. Disposing.`);
270-
this.realtimeService.docLifecycleMonitor.docDestroyed(`${this.collection}:${this.id}`);
271248
this.dispose();
272249
}
273250
});

src/SIL.XForge.Scripture/ClientApp/src/xforge-common/realtime.service.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { DestroyRef, Injectable, Optional } from '@angular/core';
2-
import { filter, race, take, timer } from 'rxjs';
2+
import { filter, lastValueFrom, race, Subject, take, timer } from 'rxjs';
33
import { AppError } from 'xforge-common/exception-handling.service';
44
import { FileService } from './file.service';
55
import { DocSubscription, RealtimeDoc } from './models/realtime-doc';
@@ -36,6 +36,7 @@ export const noopDestroyRef: DestroyRef = {
3636
})
3737
export class RealtimeService {
3838
protected readonly docs = new Map<string, RealtimeDoc>();
39+
protected readonly disposingDocIds = new Map<string, Subject<void>>();
3940
protected readonly subscribeQueries = new Map<string, Set<RealtimeQuery>>();
4041

4142
constructor(
@@ -106,9 +107,9 @@ export class RealtimeService {
106107
let doc = this.docs.get(key);
107108

108109
// Handle documents that currently exist but are in the process of being disposed.
109-
if (doc?.isDisposing) {
110+
if (doc != null && this.disposingDocIds.has(doc.id)) {
110111
console.log(`Waiting for document ${key} to be disposed before recreating it.`);
111-
await doc.disposeCompleted;
112+
await lastValueFrom(this.disposingDocIds.get(doc.id)!);
112113
// Recursively call this method so if multiple callers are waiting for the same document to be disposed, they will
113114
// all get the same instance.
114115
return await this.get<T>(collection, id, subscriber);
@@ -127,7 +128,7 @@ export class RealtimeService {
127128
});
128129
}
129130
this.docs.set(key, doc);
130-
this.docLifecycleMonitor.docCreated(`${collection}:${id}`, subscriber.callerContext);
131+
this.docLifecycleMonitor.docCreated(getDocKey(collection, id), subscriber.callerContext);
131132
}
132133
doc.addSubscriber(subscriber);
133134

@@ -249,10 +250,24 @@ export class RealtimeService {
249250
}
250251
}
251252

253+
onDocDisposeStarted(doc: RealtimeDoc): void {
254+
this.disposingDocIds.set(doc.id, new Subject<void>());
255+
this.docLifecycleMonitor.docDestroyed(getDocKey(doc.collection, doc.id));
256+
this.docs.delete(getDocKey(doc.collection, doc.id));
257+
}
258+
252259
async onLocalDocDispose(doc: RealtimeDoc): Promise<void> {
253260
if (this.isSet(doc.collection, doc.id)) {
254261
await this.offlineStore.delete(doc.collection, doc.id);
255-
this.docs.delete(getDocKey(doc.collection, doc.id));
262+
}
263+
}
264+
265+
onDocDisposeFinished(doc: RealtimeDoc): void {
266+
const disposingDocId = this.disposingDocIds.get(doc.id);
267+
if (disposingDocId != null) {
268+
disposingDocId.next();
269+
disposingDocId.complete();
270+
this.disposingDocIds.delete(doc.id);
256271
}
257272
}
258273

0 commit comments

Comments
 (0)