Class: ProcessWatcher::Watcher

Inherits:
Object
  • Object
show all
Defined in:
lib/process_watcher/watcher.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max_bytes, max_seconds) ⇒ Watcher

Initialize attributes

max_bytes(Integer)

Maximum size in bytes of watched directory before process is killed

max_seconds(Integer)

Maximum number of elapased seconds before external process is killed



60
61
62
63
# File 'lib/process_watcher/watcher.rb', line 60

def initialize(max_bytes, max_seconds)
  @max_bytes   = max_bytes
  @max_seconds = max_seconds
end

Instance Attribute Details

#max_bytesObject (readonly)

Maximum size in bytes of watched directory before process is killed



53
54
55
# File 'lib/process_watcher/watcher.rb', line 53

def max_bytes
  @max_bytes
end

#max_secondsObject (readonly)

Maximum number of elapased seconds before external process is killed



54
55
56
# File 'lib/process_watcher/watcher.rb', line 54

def max_seconds
  @max_seconds
end

Instance Method Details

#launch_and_watch(cmd, args, dest_dir) ⇒ Object

Launch given command as external process and watch given directory so it doesn’t exceed given size. Also watch time elapsed and kill external process if either the size of the watched directory exceed Note: This method is not thread-safe, instantiate one watcher per thread

Parameters

cmd(String)

command to run

args(Array)

arguments for cmd

dest_dir(String)

Watched directory

Return

res(RightScale::WatchStatus)

Outcome of watch, see RightScale::WatchStatus



78
79
80
81
82
83
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
112
113
114
115
116
# File 'lib/process_watcher/watcher.rb', line 78

def launch_and_watch(cmd, args, dest_dir)
  exit_code = nil
  output    = ''
  monitor   = ProcessMonitor.new

  # Run external process and monitor it in a new thread, platform specific
  pid = monitor.spawn(cmd, *args) do |data|
    output << data[:output] if data[:output]
    exit_code = data[:exit_code] if data.include?(:exit_code)
  end

  # Loop until process is done or times out or takes too much space
  timed_out = repeat(1, @max_seconds) do
    if @max_bytes < 0
      exit_code
    else
      size = 0
      Find.find(dest_dir) { |f| size += File.stat(f).size rescue 0 if File.file?(f) } if File.directory?(dest_dir)
      size > @max_bytes || exit_code
    end
  end

  # Cleanup and report status
  # Note: We need to store the exit status before we kill the underlying process so that
  # if it finished in the mean time we still report -1 as exit code
  if exit_code
    exit_status = exit_code
    outcome = :success
  else
    exit_status = -1
    outcome = (timed_out ? :timeout : :size_exceeded)
    Process.kill('INT', pid)
  end

  # Cleanup any open handle etc., platform specific
  monitor.cleanup

  res = WatchStatus.new(outcome, exit_status, output)
end