Class: Wurk::Swarm::RestartCounters
- Inherits:
-
Object
- Object
- Wurk::Swarm::RestartCounters
- Defined in:
- lib/wurk/swarm/restart_counters.rb
Overview
The supervisor's child-restart counts and current crash streak, for the
/metrics of whichever child owns the health port. The parent runs no
listener and has no Redis key of its own, so it writes them into an
unlinked file it opened before the first fork: every child, respawns
included, inherits the descriptor and reads the parent's latest write
with one pread. No Redis key, no socket.
One writer (the supervise thread) and a fixed 40-byte record at offset 0. A pread racing the pwrite can mix fields from the two records; each field is still a value it held (counters only grow), so a scrape never exports one that never existed, and the next scrape reads the settled record.
Defined Under Namespace
Classes: Snapshot
Constant Summary collapse
- REASONS =
%i[crash recycle liveness rolling].freeze
- FORMAT =
'Q<5'- SIZE =
8 * (REASONS.size + 1)
Class Method Summary collapse
-
.open(dir = ::Dir.tmpdir, logger: nil) ⇒ Object
nil when no temp file can be opened; the swarm runs without the metric.
Instance Method Summary collapse
- #close ⇒ Object
- #crash_streak=(streak) ⇒ Object
-
#initialize(file) ⇒ RestartCounters
constructor
A new instance of RestartCounters.
-
#read ⇒ Object
The parent's latest record; nil when it cannot be read.
- #record_restart(reason) ⇒ Object
Constructor Details
#initialize(file) ⇒ RestartCounters
Returns a new instance of RestartCounters.
37 38 39 40 41 42 |
# File 'lib/wurk/swarm/restart_counters.rb', line 37 def initialize(file) @io = file @restarts = REASONS.to_h { |reason| [reason, 0] } @crash_streak = 0 write end |
Class Method Details
.open(dir = ::Dir.tmpdir, logger: nil) ⇒ Object
nil when no temp file can be opened; the swarm runs without the metric.
27 28 29 30 31 32 33 34 35 |
# File 'lib/wurk/swarm/restart_counters.rb', line 27 def self.open(dir = ::Dir.tmpdir, logger: nil) path = ::File.join(dir, "wurk-swarm-#{::Process.pid}-#{::SecureRandom.hex(6)}") file = ::File.new(path, ::File::RDWR | ::File::CREAT | ::File::EXCL, 0o600) ::File.unlink(path) new(file) rescue ::SystemCallError => e logger&.warn { "swarm: restart counters unavailable (#{e.class}: #{e.}); not exported" } nil end |
Instance Method Details
#close ⇒ Object
66 67 68 |
# File 'lib/wurk/swarm/restart_counters.rb', line 66 def close @io.close unless @io.closed? end |
#crash_streak=(streak) ⇒ Object
49 50 51 52 53 54 |
# File 'lib/wurk/swarm/restart_counters.rb', line 49 def crash_streak=(streak) return if streak == @crash_streak @crash_streak = streak write end |
#read ⇒ Object
The parent's latest record; nil when it cannot be read.
57 58 59 60 61 62 63 64 |
# File 'lib/wurk/swarm/restart_counters.rb', line 57 def read values = @io.pread(SIZE, 0)&.unpack(FORMAT) return nil unless values && values.size == SIZE / 8 Snapshot.new(REASONS.zip(values).to_h, values.last) rescue ::IOError, ::SystemCallError nil end |
#record_restart(reason) ⇒ Object
44 45 46 47 |
# File 'lib/wurk/swarm/restart_counters.rb', line 44 def record_restart(reason) @restarts[REASONS.include?(reason) ? reason : :crash] += 1 write end |