Repository navigation
Fail self.deferred in connectionLost instead of hanging forever - #543
Conversation
captureScreen/captureRegion, expectScreen/expectRegion, refreshScreen and stableScreen/stableRegion each park one pending operation in self.deferred (or, for the stable-watch commands, ride on it indirectly). None of them learned about a dropped connection: the Deferred a caller was waiting on simply never fired, so a disconnect mid-capture hung the caller rather than failing it. connectionLost now errbacks self.deferred with a new ConnectionLostError when one is pending -- ProtocolError and DesktopResizeError already name a specific cause, neither of which is "the socket went away", so a new exception says that plainly. _StableWatch is the one case that needed more than an errback on self.deferred: refreshScreen's Deferred that _request chains off is one round of the watch, not the Deferred that stableScreen/stableRegion handed to their caller (_StableWatch.result, only ever fired from _settle()). Failing self.deferred alone would have hit "Unhandled error in Deferred" and left the caller hanging exactly as before, just one layer down. _request now adds an errback alongside its callback that fails self.result directly, cancelling the pending settle timer so a stale timer cannot later call back an already-errored Deferred. For refreshScreen/_capture/expectScreen, no such wiring was needed: those hand the caller self.deferred itself (or a Deferred Twisted chains onto it across rounds), so errbacking self.deferred already reaches the caller through Twisted's ordinary Deferred-returning- Deferred chaining. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9XU3qUSZYysSFCZNaRpQc
c8bcfa7 to
0ee30c2
Compare
|
Cause, measured since on draft #546: TightVNC serves an all-black frame (every tile a Tight fill of I can't re-run the failed job (403), so this PR stays watched. Generated by Claude Code |
The bool flipped to True in exactly the two places the caller's Deferred fired (_settle's callback, _disconnected's errback), so it restated Deferred.called under a second name. Keep one: the Deferred is now `settled`, and the re-arm guards test `settled.called`. "Settled" in the promise sense covers both outcomes, which is what the disconnect path added. `result` was too generic a name for it, per review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
capture,expect,refreshScreenandstableall wait onself.deferred, and none of them learned about a dropped connection, so a disconnect mid-call hung the caller.connectionLostnow errbacks a pendingself.deferredwith a newConnectionLostError._StableWatchhands its caller a separate Deferred, fired by a timer rather than by an update, so_requestalso errbacks that one and cancels the timer. Review renamed itresult→settledand dropped the bool that duplicatedsettled.called.resizeScreenkeeps its own_PendingResizeDeferred: it completes on the server's ExtendedDesktopSize reply, not oncommitUpdate, so it can't share the slot.connectionLostchecks both, which is where this conflicted with #497.🤖 Generated with Claude Code