Class: HotCell::Transport::Socket

Inherits:
Object
  • Object
show all
Defined in:
lib/hot_cell/transport.rb

Instance Method Summary collapse

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.send_message 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