Closed raimohanska closed 5 months ago
Thanks a lot for this @raimohanska!
I think I've found a way (I'm just using the debouncer in storeDocumentHooks), but will need to do some testing. I haven't reproduced your issue yet, but it makes sense. I'm spending some time now testing / reproducing it.
aha! This only happens when you start a transaction and pass an origin, otherwise it works (L404 in Hocuspocus.ts is the guard).
I've pushed a fix in #834 and added a reproduction test case. Can you verify if that works for you? 🙏
Great, thanks! I'll have a look tomorrow and see if I can verify the fix.
Btw the redis-specific check on L404 looks quite hacky 😂
Description
If you use a
DirectConnection
when there are no WebSocket connections for a document, the WebSocket connections established during the next 2 seconds (or debounce time) will end up using an orphaned document and will not sync changes properly with clients that establish connections after that 2 second period. The problem lies in thatstoreDocumentHooks
is called directly after closing the DirectConnection, but also in a debounced manner a bit later. Details follow.Steps to reproduce the bug
doc1
.storeDocumentHooks
has now beed called twice (once for the (transact
and once for thedisconnect
). As the result of the latter, theunloadDocument
method has been called and thedoc1
has beed removed fromthis.documents
storeDocumentHooks
to be performed in 2 seconds or so.doc1
is not loaded yet, it will now be loadedstoreDocumentHooks
call kicks in. This call is bound to the earlierY.Doc
instance that no longer is referenced inthis.documents
(there's no a new copy ofdoc1
loaded). This call results into another call tounloadDocument
which, on this line removed the document fromthis.documents
. Unfortunately, it ends up removing the new document instance, which is now referenced by the WebSocket client which connected in step 5.this.documents
. Any client connecting from now on, will be assigned to a new document instance and the clients will not see changes from each other.Expected behavior
When the DirectConnection is closed and there are no more clients for
doc1
, we should not unload the document when there is still a debounced storeDocumentHooks call left to be performed. Or alternatively, at least make sure that the debounced call does not end up removing the newer, active document fromthis.documents
.In my project, I made a quick patch for this line to additionally check that the document currently in
this.docs
is actually same document that's now being unloaded.The patch solution is suboptimal though at least in the sense that two copies of the same document will exist in server memory for a time. I'd prolly rather have it so that the document accessed by DirectConnection would be subject to the same lifecycle as with WebSocket connections - that is, to be unloaded only after the normal debounce period. Yet, I'm not intimately familiar with the server design, so my hunch may be misguided.