Class: HotCell::Transport::Socket
- Inherits:
-
Object
- Object
- HotCell::Transport::Socket
- Defined in:
- lib/hot_cell/transport.rb
Instance Method Summary collapse
-
#call(cell, line, descriptors, socket: cell.work_socket, timeout: cell.timeout) ⇒ Object
Accepted risk.
timeoutcovers the answer and not the connection.
Instance Method Details
#call(cell, line, descriptors, socket: cell.work_socket, timeout: cell.timeout) ⇒ Object
Accepted risk. timeout covers the answer and not the connection. UNIXSocket.new blocks, and
connect to a Unix socket blocks while the listener's backlog is full — a supervisor that is alive
and no longer calling accept. A caller can be held there with no bound, on a path an application
may be calling from a web request.
The premise is that the state is nearly unreachable rather than tolerable. A supervisor that dies
gives ECONNREFUSED, not a hang, so this needs one that lives and stops accepting — and the loop is
built to make that not happen: Log#emit writes non-blocking so a stalled container log pipe cannot
park it, and a recursive delete is renamed out of the loop rather than performed inside it. Bounding
it means connect_nonblock plus wait_writable against the deadline receive already builds, which
is worth doing the day this is observed and not before.
24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/hot_cell/transport.rb', line 24 def call(cell, line, descriptors, socket: cell.work_socket, timeout: cell.timeout) connection = Connection.new(UNIXSocket.new(socket)) connection. line, descriptors: descriptors receive connection, timeout rescue SystemCallError, IOError => error # A socket that does not exist, a cell that is restarting, an accessory not yet booted. These are # the most likely failures in production and they produce no wire response at all, so they belong # in the taxonomy rather than outside it — otherwise the code on the instrumentation event is blank # for exactly the outage you most want to see. unavailable error ensure connection&.close end |