Class: HotCell::Client

Inherits:
Object
  • Object
show all
Extended by:
Declarations
Defined in:
lib/hot_cell/client.rb,
lib/hot_cell/client/version.rb

Overview

A class and not a module: this file loads before hot_cell/client.rb opens the same name.

Constant Summary collapse

INPUT_MODE =

What a shared group is narrowed to on the way out, and the reason the group is safe to give away. A cell may read an input and never write one; it may write an output and never read one. The kernel applies these on every re-open by name, and the cell cannot widen either — changing a mode needs ownership, the caller owns these files, and cap-drop ALL leaves no capability that overrides it.

0o640
OUTPUT_MODE =
0o620
VERSION =
"0.1.0"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.cellObject

Raises:

  • (ConfigurationError)


60
61
62
63
64
65
# File 'lib/hot_cell/client.rb', line 60

def cell
  name = hotcell
  raise ConfigurationError, "#{self} must name its cell with `hotcell \"a_name\"`" if name.nil?

  HotCell.cell name
end

.enabled?Boolean

Whether this path is turned on. A caller that finds it off runs in process exactly as it did before, which is the whole rollout mechanism.

Returns:

  • (Boolean)


75
76
77
# File 'lib/hot_cell/client.rb', line 75

def enabled?
  cell.enabled?
end

.hotcell(name = nil) ⇒ Object



48
49
50
51
52
# File 'lib/hot_cell/client.rb', line 48

def hotcell(name = nil)
  return inherited_value(:@cell_name) if name.nil?

  @cell_name = name.to_s
end

.inherited(subclass) ⇒ Object



43
44
45
46
# File 'lib/hot_cell/client.rb', line 43

def inherited(subclass)
  super
  HotCell.clients << subclass
end

.operation(name = nil) ⇒ Object



54
55
56
57
58
# File 'lib/hot_cell/client.rb', line 54

def operation(name = nil)
  return @operation_name || Naming.default_operation_name(self) if name.nil?

  @operation_name = name.to_s
end

.perform_in_hotcell(inputs, outputs, payload = {}) ⇒ Object



79
80
81
# File 'lib/hot_cell/client.rb', line 79

def perform_in_hotcell(inputs, outputs, payload = {})
  new.perform_in_hotcell inputs, outputs, payload
end

.registered?Boolean

Whether this client's named cell is registered, for a boot-time hook that must not raise on an application that has bundled the gem and not yet written the initializer.

Returns:

  • (Boolean)


69
70
71
# File 'lib/hot_cell/client.rb', line 69

def registered?
  !hotcell.nil? && HotCell.cell?(hotcell)
end

Instance Method Details

#perform_in_hotcell(inputs, outputs, payload = {}) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/hot_cell/client.rb', line 84

def perform_in_hotcell(inputs, outputs, payload = {})
  # Explicit wrapping rather than Array(): an IO is Enumerable, so Array(io) reads the stream line by
  # line instead of wrapping it.
  inputs = [ inputs ] unless inputs.is_a?(Array)
  outputs = [ outputs ] unless outputs.is_a?(Array)

  cell = self.class.cell

  unless cell.enabled?
    raise CellNotConfigured, "cell #{cell.name.inspect} has no socket directory, so this path is off"
  end

  # Everything up to here raises for itself, above the transport's rescue and on purpose. A payload
  # value JSON cannot carry, a descriptor with the wrong access mode, or a request over the byte limit
  # are this caller's bugs. An application whose transient class descends from IOError would otherwise
  # have its own bad call reclassified as a socket failure and retried forever.
  descriptors = wrap(inputs, outputs)
  line = request_line(inputs, outputs, payload)

  response = nil
  ActiveSupport::Notifications.instrument "perform.hot_cell" do |event|
    response = verify_output(cell.transport.call(cell, line, descriptors), outputs)
    publish event, cell, response, inputs, outputs
  end

  raise_for response, cell
  response.result
end