… it unpredictable
This is fairly edge-case-y but could bite someone. If you'd set a watch when doing a get that failed because the node didn't exist, any subsequent attempts to set a watch would fail silently, because the client thought that the watch had already been set. We now wrap the operation in the setup_watcher! method, which rolls back the record-keeping of what watches have already been set for what nodes if an exception is raised. This change has the side-effect that certain operations (get,stat,exists?,children) will block event delivery until completion, because they need to have a consistent idea about what events are pending, and which have been delivered. This also means that calling these methods represent a synchronization point between user threads (these operations can only occur serially, not simultaneously).
…, but do not deadlock Rather than deadlocking and causing problems, we will vomit with an error and print a Kernel.warn message so *hopefully* the user will see one of those and realize they've done something wrong. The only alternative at this point would be to call exit! which would be unconscionably horrendous, or some hack that would raise an exception (at random) in the main thread (which would be dangerous and stupid).
This change is so that errors in user-supplied callbacks will be logged *somewhere* possibly visible to the user.
…d in the dispatch thread
(if the event handler could handle events)
… a client.
…a lot of stuff, revert it
…thread this would cause events to never get delivered ever again, and the client might never be aware of the condition (until they realize no events are getting delivered) with specs
…vant underlying exceptions