def start_parent
parent_pid = fork do
self.child_processes = Hash.new
$0="#{self.config.name}[Parent]"
logger.info "New parent process: #{Process.pid}"
STDOUT.flush
if config.before_fork.is_a?(Proc)
self.config.before_fork.call
end
self.fork_workers(self.config.workers)
Signal.trap("TERM", proc {
logger.info "Parent got a TERM."
STDOUT.flush
kill_child_processes
Process.exit(0)
})
Signal.trap('INT', proc {})
Signal.trap('HUP', proc {})
loop do
sleep 2
child_processes.dup.each do |id, opts|
begin
Process.getpgid(opts[:pid])
if config.memory_limit
memory_usage = `ps -o rss= -p #{opts[:pid]}`.strip.to_i / 1024
if memory_usage > config.memory_limit
logger.info "#{self.config.name}[#{id}] is using #{memory_usage}MB of memory (limit: #{config.memory_limit}MB). It will be killed."
kill_child_process(id)
end
end
rescue Errno::ESRCH
logger.info "Child process #{config.name}[#{id}] has died (from PID #{opts[:pid]})"
child_processes[id][:pid] = nil
if config.respawn
if opts[:started_at] > Time.now - config.respawn_limits[1]
if opts[:respawns] >= config.respawn_limits[0]
logger.info "Process #{config.name}[#{id}] has instantly respawned #{opts[:respawns]} times. It won't be respawned again."
child_processes.delete(id)
else
logger.info "Process has died within #{config.respawn_limits[1]}s of the last spawn."
child_processes[id][:respawns] += 1
fork_worker(id)
end
else
logger.info "Process was started more than #{config.respawn_limits[1]}s since the last spawn. Resetting spawn counter"
child_processes[id][:respawns] = 0
fork_worker(id)
end
else
child_processes.delete(id)
end
end
end
if child_processes.empty?
logger.info "All child processes died, exiting parent"
Process.exit(0)
end
end
end
child_processes[0] = {:pid => parent_pid, :respawns => 0}
Process.detach(parent_pid)
end