@@ -62,6 +62,7 @@ export class Hocuspocus {
6262 } ;
6363
6464 loadingDocuments : Map < string , Promise < Document > > = new Map ( ) ;
65+ unloadingDocuments : Map < string , Promise < void > > = new Map ( ) ;
6566
6667 documents : Map < string , Document > = new Map ( ) ;
6768
@@ -440,7 +441,7 @@ export class Hocuspocus {
440441 this . debouncer . isDebounced ( debounceId ) ||
441442 document . saveMutex . isLocked ( ) ;
442443 const shouldUnload =
443- document . getConnectionsCount ( ) == 0 && ! hasPendingWork ;
444+ document . getConnectionsCount ( ) === 0 && ! hasPendingWork ;
444445 if ( shouldUnload ) {
445446 this . unloadDocument ( document ) ;
446447 }
@@ -493,25 +494,41 @@ export class Hocuspocus {
493494
494495 async unloadDocument ( document : Document ) : Promise < any > {
495496 const documentName = document . name ;
496- if ( ! this . documents . has ( documentName ) ) return ;
497497
498- try {
499- await this . hooks ( "beforeUnloadDocument" , {
500- instance : this ,
501- documentName,
502- document,
503- } ) ;
504- } catch ( e ) {
498+ if ( ! this . documents . has ( documentName ) || document . saveMutex . isLocked ( ) )
505499 return ;
506- }
507500
508- if ( document . getConnectionsCount ( ) > 0 ) {
509- return ;
510- }
501+ if ( this . unloadingDocuments . has ( documentName ) )
502+ return this . unloadingDocuments . get ( documentName ) ;
503+
504+ // we need to make sure that the logic runs just once, even if multiple clients disconnect together
505+ const actualUnloadingLogic = async ( ) => {
506+ try {
507+ await this . hooks ( "beforeUnloadDocument" , {
508+ instance : this ,
509+ documentName,
510+ document,
511+ } ) ;
512+ } catch ( e ) {
513+ return ;
514+ }
515+
516+ if ( document . getConnectionsCount ( ) > 0 ) {
517+ return ;
518+ }
519+
520+ this . documents . delete ( documentName ) ;
521+ document . destroy ( ) ;
522+ await this . hooks ( "afterUnloadDocument" , { instance : this , documentName } ) ;
523+ } ;
524+
525+ const unloading = actualUnloadingLogic ( ) ;
526+
527+ this . unloadingDocuments . set ( documentName , Promise . resolve ( unloading ) ) ;
528+
529+ await unloading ;
511530
512- this . documents . delete ( documentName ) ;
513- document . destroy ( ) ;
514- await this . hooks ( "afterUnloadDocument" , { instance : this , documentName } ) ;
531+ this . unloadingDocuments . delete ( documentName ) ;
515532 }
516533
517534 async openDirectConnection (
0 commit comments