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



40
41
42
43
44
# File 'lib/zeusd/process.rb', line 40

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

.find(pid) ⇒ Object



54
55
56
57
58
# File 'lib/zeusd/process.rb', line 54

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

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



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/zeusd/process.rb', line 68

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



25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/zeusd/process.rb', line 25

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



60
61
62
63
64
65
66
# File 'lib/zeusd/process.rb', line 60

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



46
47
48
49
50
51
52
# File 'lib/zeusd/process.rb', line 46

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)


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

def alive?
  reload!
  !attributes.empty?
end

#asleep?Boolean

Returns:

  • (Boolean)


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

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

#commandObject



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

def command
  attributes["command"]
end

#cwdObject



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

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)


123
124
125
# File 'lib/zeusd/process.rb', line 123

def dead?
  !alive?
end

#descendants(options = {}) ⇒ Object



138
139
140
141
142
# File 'lib/zeusd/process.rb', line 138

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

#kill!(options = {}) ⇒ Object



127
128
129
130
131
132
133
134
135
136
# File 'lib/zeusd/process.rb', line 127

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



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

def pgid
  attributes["pgid"]
end

#pidObject



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

def pid
  attributes["pid"]
end

#ppidObject



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

def ppid
  attributes["ppid"]
end

#reload!Object



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

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

#stateObject



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

def state
  reload!
  attributes["stat"]
end

#to_json(*args) ⇒ Object



21
22
23
# File 'lib/zeusd/process.rb', line 21

def to_json(*args)
  attributes.to_json(*args)
end