Skip to content

Commit 8f86caf

Browse files
authored
feat: rewrite of redis unloading logic to utilize before/after-unloadDocument (#1007)
1 parent 31896d8 commit 8f86caf

File tree

1 file changed

+17
-39
lines changed

1 file changed

+17
-39
lines changed

packages/extension-redis/src/Redis.ts

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import type {
55
Hocuspocus,
66
afterLoadDocumentPayload,
77
afterStoreDocumentPayload,
8+
afterUnloadDocumentPayload,
89
beforeBroadcastStatelessPayload,
10+
beforeUnloadDocumentPayload,
911
onAwarenessUpdatePayload,
1012
onChangePayload,
1113
onConfigurePayload,
12-
onDisconnectPayload,
1314
onStoreDocumentPayload,
1415
} from "@hocuspocus/server";
1516
import {
@@ -108,12 +109,6 @@ export class Redis implements Extension {
108109

109110
messagePrefix: Buffer;
110111

111-
/**
112-
* When we have a high frequency of updates to a document we don't need tons of setTimeouts
113-
* piling up, so we'll track them to keep it to the most recent per document.
114-
*/
115-
private pendingDisconnects = new Map<string, NodeJS.Timeout>();
116-
117112
private pendingAfterStoreDocumentResolves = new Map<
118113
string,
119114
{ timeout: NodeJS.Timeout; resolve: () => void }
@@ -389,42 +384,25 @@ export class Redis implements Extension {
389384
}
390385

391386
/**
392-
* Make sure to *not* listen for further changes, when there’s
393-
* no one connected anymore.
387+
* Delay unloading to allow syncs to finish
394388
*/
395-
public onDisconnect = async ({ documentName }: onDisconnectPayload) => {
396-
const pending = this.pendingDisconnects.get(documentName);
397-
398-
if (pending) {
399-
clearTimeout(pending);
400-
this.pendingDisconnects.delete(documentName);
401-
}
402-
403-
const disconnect = () => {
404-
const document = this.instance.documents.get(documentName);
405-
406-
this.pendingDisconnects.delete(documentName);
407-
408-
// Do nothing, when other users are still connected to the document.
409-
if (document && document.getConnectionsCount() > 0) {
410-
return;
411-
}
389+
async beforeUnloadDocument(data: beforeUnloadDocumentPayload) {
390+
return new Promise<void>((resolve) => {
391+
setTimeout(() => {
392+
resolve();
393+
}, this.configuration.disconnectDelay);
394+
});
395+
}
412396

413-
// Time to end the subscription on the document channel.
414-
this.sub.unsubscribe(this.subKey(documentName), (error: any) => {
415-
if (error) {
416-
console.error(error);
417-
}
418-
});
397+
async afterUnloadDocument(data: afterUnloadDocumentPayload) {
398+
if (data.instance.documents.has(data.documentName)) return; // skip unsubscribe if the document is already loaded again (maybe fast reconnect)
419399

420-
if (document) {
421-
this.instance.unloadDocument(document);
400+
this.sub.unsubscribe(this.subKey(data.documentName), (error: any) => {
401+
if (error) {
402+
console.error(error);
422403
}
423-
};
424-
// Delay the disconnect procedure to allow last minute syncs to happen
425-
const timeout = setTimeout(disconnect, this.configuration.disconnectDelay);
426-
this.pendingDisconnects.set(documentName, timeout);
427-
};
404+
});
405+
}
428406

429407
async beforeBroadcastStateless(data: beforeBroadcastStatelessPayload) {
430408
const message = new OutgoingMessage(

0 commit comments

Comments
 (0)