Module: Agent::Lock::ProcessInfo

Defined in:
lib/agent/lock/process_info.rb

Overview

The three questions this gem asks the operating system about a process: what it is called, who its parent is, and when it started.

ps rather than /proc, because this has to work the same on macOS and on Linux, and because none of it is on a hot path. Every answer is nil when the process is gone, which callers read as "no longer running".

Class Method Summary collapse

Class Method Details

.alive?(pid, started: nil) ⇒ Boolean

Returns whether that exact process is still running.

Parameters:

  • pid (Integer, nil)
  • started (String, nil) (defaults to: nil) —

    as recorded when the lock was taken

Returns:

  • (Boolean) —

    whether that exact process is still running



38
39
40
41
42
43
44
45
46
# File 'lib/agent/lock/process_info.rb', line 38

def alive?(pid, started: nil)
  return false if pid.nil?

  now = started_at(pid)
  return false if now.nil?
  return true if started.nil? || started.empty?

  now == started
end

.command(pid) ⇒ String?

Returns the executable's name, without its path.

Parameters:

  • pid (Integer)

Returns:

  • (String, nil) —

    the executable's name, without its path



16
17
18
19
# File 'lib/agent/lock/process_info.rb', line 16

def command(pid)
  value = ps(pid, "comm")
  value && File.basename(value)
end

.parent_of(pid) ⇒ Integer?

Parameters:

  • pid (Integer)

Returns:

  • (Integer, nil)


23
24
25
26
# File 'lib/agent/lock/process_info.rb', line 23

def parent_of(pid)
  value = ps(pid, "ppid")
  value && Integer(value, exception: false)
end

.ps(pid, field) ⇒ String?

Returns the field, or nil for a process that is gone.

Returns:

  • (String, nil) —

    the field, or nil for a process that is gone



49
50
51
52
53
54
55
56
57
# File 'lib/agent/lock/process_info.rb', line 49

def ps(pid, field)
  return nil if pid.nil?

  out = IO.popen(["ps", "-p", pid.to_s, "-o", "#{field}="], err: File::NULL, &:read)
  out = out.to_s.strip
  out.empty? ? nil : out
rescue SystemCallError
  nil
end

.started_at(pid) ⇒ String?

The wall-clock start time, which is what tells a live process from a different one that inherited its recycled pid.

Parameters:

  • pid (Integer)

Returns:

  • (String, nil)


33
# File 'lib/agent/lock/process_info.rb', line 33

def started_at(pid) = ps(pid, "lstart")