diff options
author | Sam Thursfield <sam.thursfield@codethink.co.uk> | 2015-01-14 18:19:22 +0200 |
---|---|---|
committer | Baserock Gerrit <gerrit@baserock.org> | 2015-05-15 14:38:05 +0000 |
commit | 4131947a0a5a9957c76cf03264e67cbcc1494d4b (patch) | |
tree | e0ff2f93d387f73ede5c29b9493a38d9e2bef753 /distbuild/jm.py | |
parent | 8625124549dd4ae1a5b347a51c95c3f1887fb9ea (diff) | |
download | morph-4131947a0a5a9957c76cf03264e67cbcc1494d4b.tar.gz |
distbuild: Handle errors from socket
We found a distbuild controller stuck in a busy loop, with the logs
full of the same error message repeated:
... _flush(): Exception 'IOError: [Errno 32] Broken pipe' from sock.write()
We suspect this came about because the initiator disconnected without
sending an EOF. The initiator was in a VM on a laptop so it seems
possible that the host OS turned off the wireless adaptor without giving
the VM a chance to close its connections gracefully.
The busy loop is because nothing in the SocketBuffer class handles the
SocketError events queued by the _flush() method. Unhandled events are
ignored. So the SocketBuffer stays in 'w' state without ever shifting
any data and never returns. Adding transitions to handle the SocketError
event will fix the problem.
If a socket error happens now in the same scenario, it will be handled
as if the initiator disconnected.
Change-Id: I0f6834f7186a01ca2bc74aef899a4cccbc891e51
Diffstat (limited to 'distbuild/jm.py')
-rw-r--r-- | distbuild/jm.py | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/distbuild/jm.py b/distbuild/jm.py index c08a1958..d1e5fab7 100644 --- a/distbuild/jm.py +++ b/distbuild/jm.py @@ -38,8 +38,17 @@ class JsonNewMessage(object): class JsonEof(object): pass - - + + +class JsonError(object): + + '''An error has occured with a socket used for communication.''' + + def __init__(self, sock, exception): + self.sock = sock + self.exception = exception + + class _Close2(object): pass @@ -71,9 +80,12 @@ class JsonMachine(StateMachine): # state, source, event_class, new_state, callback ('rw', sockbuf, SocketBufferNewData, 'rw', self._parse), ('rw', sockbuf, SocketBufferEof, 'w', self._send_eof), + ('rw', sockbuf, SocketError, 'error', self._send_error), ('rw', self, _Close2, None, self._really_close), ('w', self, _Close2, None, self._really_close), + + ('error', self, _Close2, None, self._really_close) ] self.add_transitions(spec) @@ -119,6 +131,9 @@ class JsonMachine(StateMachine): def _send_eof(self, event_source, event): self.mainloop.queue_event(self, JsonEof()) + def _send_error(self, event_source, event): + self.mainloop.queue_event(self, JsonError(event.sock, event.exception)) + def _really_close(self, event_source, event): self.sockbuf.close() self._send_eof(event_source, event) |