Class: Zeusd::Process

Inherits:
Object
  • Object
show all
Defined in:
lib/zeusd/process.rb

Constant Summary collapse

CASTINGS =
{
  "pid"     => ->(x){x.to_i},
  "ppid"    => ->(x){x.to_i},
  "pgid"    => ->(x){x.to_i},
  "stat"    => ->(x){x.to_s},
  "command" => ->(x){x.to_s}
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes_or_pid) ⇒ Process

Returns a new instance of Process.



12
13
14
15
16
17
18
19
# File 'lib/zeusd/process.rb', line 12

def initialize(attributes_or_pid)
  if attributes_or_pid.is_a? Hash
    self.attributes = attributes_or_pid
  else
    self.attributes = {"pid" => attributes_or_pid.to_i}
    reload!
  end
end

Instance Attribute Details

#attributesObject

Returns the value of attribute attributes.



10
11
12
# File 'lib/zeusd/process.rb', line 10

def attributes
  @attributes
end

#children(options = {}) ⇒ Object

Returns the value of attribute children.



10
11
12
# File 'lib/zeusd/process.rb', line 10

def children
  @children
end

Class Method Details

.all(options = {}) ⇒ Object



36
37
38
39
40
# File 'lib/zeusd/process.rb', line 36

def self.all(options = {})
  ps(options).map do |attributes|
    self.new(attributes)
  end
end

.find(pid) ⇒ Object



50
51
52
53
54
# File 'lib/zeusd/process.rb', line 50

def self.find(pid)
  if attributes = ps(:pid => pid).first
    self.new(attributes)
  end
end

.kill!(pids, options = {}) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/zeusd/process.rb', line 64

def self.kill!(pids, options = {})
  pids      = Array(pids).map(&:to_i).select{|x| x > 0}
  processes = pids.map{|pid| self.new(pid)}
  signal    = options.fetch(:signal, "TERM")
  wait      = options.fetch(:wait, false)
  return false if processes.any?(&:dead?)

  if system("kill -#{signal} #{processes.map(&:pid).join(' ')}")
    self.wait(pids) if wait
    true
  else
    false
  end
end

.ps(options = {}) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/zeusd/process.rb', line 21

def self.ps(options = {})
  keywords = Array(options[:keywords]) | %w[pid ppid pgid stat command]
  command  = ["ps"].tap do |ps|
    ps << "-o #{keywords.join(',')}"
    ps << "-p #{options[:pid].to_i}" if options[:pid]
  end.join(" ")
  header, *rows = `#{command}`.split("\n")
  keys          = header.downcase.split
  glob_columns  = 0...(keys.length-1)
  cmd_columns   = (keys.length-1)..-1
  Array(rows.map(&:split)).map do |parts|
    Hash[keys.zip(parts[glob_columns] << parts[cmd_columns].join(" "))] # Attributes
  end
end

.wait(pids = []) ⇒ Object



56
57
58
59
60
61
62
# File 'lib/zeusd/process.rb', line 56

def self.wait(pids = [])
  pids = Array(pids).map(&:to_s)
  loop do
    break if (self.ps.map{|x| x["pid"]} & pids).length.zero?
    sleep(0.1)
  end
end

.where(criteria, options = {}) ⇒ Object



42
43
44
45
46
47
48
# File 'lib/zeusd/process.rb', line 42

def self.where(criteria, options = {})
  all(options).select do |process|
    criteria.all? do |key, value|
      process.send(key) == value
    end
  end
end

Instance Method Details

#alive?Boolean

Returns:

  • (Boolean)


114
115
116
117
# File 'lib/zeusd/process.rb', line 114

def alive?
  reload!
  !attributes.empty?
end

#asleep?Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/zeusd/process.rb', line 110

def asleep?
  !!state.to_s["S"]
end

#commandObject



106
107
108
# File 'lib/zeusd/process.rb', line 106

def command
  attributes["command"]
end

#cwdObject



85
86
87
# File 'lib/zeusd/process.rb', line 85

def cwd
  @cwd ||= (path = `lsof -p #{pid}`.split("\n").find{|x| x[" cwd "]}.split.last.strip) ? Pathname.new(path).realpath : nil
end

#dead?Boolean

Returns:

  • (Boolean)


119
120
121
# File 'lib/zeusd/process.rb', line 119

def dead?
  !alive?
end

#descendants(options = {}) ⇒ Object



134
135
136
137
138
# File 'lib/zeusd/process.rb', line 134

def descendants(options = {})
  children(options).map do |child_process|
    [child_process].concat(Array(child_process.descendants))
  end.flatten.compact
end

#kill!(options = {}) ⇒ Object



123
124
125
126
127
128
129
130
131
132
# File 'lib/zeusd/process.rb', line 123

def kill!(options = {})
  return false if dead?
  opts = options.dup

  pids = [pid].tap do |x|
    x.concat(descendants.map(&:pid)) if !!opts.delete(:recursive)
  end

  self.class.kill!(pids, opts)
end

#pgidObject



97
98
99
# File 'lib/zeusd/process.rb', line 97

def pgid
  attributes["pgid"]
end

#pidObject



89
90
91
# File 'lib/zeusd/process.rb', line 89

def pid
  attributes["pid"]
end

#ppidObject



93
94
95
# File 'lib/zeusd/process.rb', line 93

def ppid
  attributes["ppid"]
end

#reload!Object



79
80
81
82
83
# File 'lib/zeusd/process.rb', line 79

def reload!
  self.attributes = self.class.ps(:pid => pid).first || {}
  @children       = nil
  !attributes.empty?
end

#stateObject



101
102
103
104
# File 'lib/zeusd/process.rb', line 101

def state
  reload!
  attributes["stat"]
end