Opened 17 years ago
Last modified 9 years ago
#42 closed enhancement
notifyOnDisconnect() could use weakrefs — at Initial Version
Reported by: | Brian Warner | Owned by: | |
---|---|---|---|
Priority: | major | Milestone: | 0.12.0 |
Component: | usability | Version: | 0.2.2 |
Keywords: | disconnect | Cc: |
Description
I've been struggling with the usability aspects of notifyOnDisconnect(), which lets you attach a callback to a RemoteReference that will tell you when the other end goes away (i.e. a network partition occurs, because of a TCP connection being severed). This returns a "marker" object (really a tuple, but it should be replaced by an anonymous instance), which can be passed to the corresponding dontNotifyOnDisconnect() to remove the callback.
The problem is that managing the callback is a serious hassle. I've seen two main use cases for notifyOnDisconnect. The first is a publish/subscribe pattern, where you keep a set of RemoteReferences (that you plan to iterate over and send messages to each later on), and you want to reduce memory consumption by removing them from the set as soon as they cease being useful. (if you didn't care about the memory usage, you could always just leave them there, and catch the DeadReferenceError that will occur when you use a stale one)
The second is when the RemoteReference is used as a "canary", basically when the remote side has access to one of your own objects, and you want to find out when they lose contact with it. The Tahoe example is that clients who want to upload data contact the storage server and get access to a writer facet, to which they send a bunch of data before calling close(). If the client drops off the network before calling close(), the server is supposed to delete the partial share. To enable this, a client-side "canary" object is passed to the server, and the server uses notifyOnDisconnect to discover when the client has gone away.
E has a "reactToLostClient" method, and notifyOnDisconnect is implemented on top of it. In Foolscap we currently do it the other way around, where an application-visible canary is used, implemented on top of notifyOnDisconnect.
Anyways, the problem is that once notifyOnDisconnect is called, there will come a time when we no longer care to hear about the disconnection, and there are usually two code paths that bring this era of caring to an end: when the subscriber has removed themselves, or when the upload-like action has finished. To make sure we don't double-call dontNotifyOnDisconnect, we must keep careful track of our state, and it's easy to get it wrong.
Writing this up makes me realize that the subscription case might be handled better by not bothering with notifyOnDisconnect, and instead just leaving the RemoteReferences in the collection until they fail of their own accord (by catching DeadReferenceError). But I think the canary case is still tricky.
The idea that prompted me to write this ticket was that we might use weakrefs to make it easier to manage these callbacks. The idea would be that once everyone else has forgotten about the RemoteReference, then the Tub should too. The immediate problem that I can imagine is the uncertainty: if you've forgotten about the RR, but it hasn't been gc'ed yet, then your callback could still be fired.
hmmm.