class RackRabbit::Server
Attributes
app[R]
config[R]
killed_pids[R]
logger[R]
server_pid[R]
signals[R]
worker_pids[R]
Public Class Methods
new(options)
click to toggle source
# File lib/rack-rabbit/server.rb, line 23 def initialize(options) @config = Config.new(options) @logger = config.logger @server_pid = $$ @worker_pids = [] @killed_pids = [] @signals = Signals.new end
Public Instance Methods
check_pid()
click to toggle source
# File lib/rack-rabbit/server.rb, line 207 def check_pid pidfile = config.pidfile if pidfile case pid_status(pidfile) when :running, :not_owned logger.fatal "A server is already running. Check #{pidfile}" exit(1) when :dead File.delete(pidfile) end end end
daemonize()
click to toggle source
¶ ↑
DAEMONIZING, PID MANAGEMENT, and OUTPUT REDIRECTION
¶ ↑
# File lib/rack-rabbit/server.rb, line 170 def daemonize exit if fork Process.setsid exit if fork Dir.chdir "/" redirect_output logger.master_pid = $$ if logger.respond_to?(:master_pid) # inform logger of new master_pid so it can continue to distinguish between "SERVER" and "worker" in log preamble end
kill_all_workers(sig)
click to toggle source
# File lib/rack-rabbit/server.rb, line 132 def kill_all_workers(sig) kill_worker(sig, worker_pids.last) until worker_pids.empty? end
kill_random_worker(sig)
click to toggle source
# File lib/rack-rabbit/server.rb, line 128 def kill_random_worker(sig) kill_worker(sig, worker_pids.sample) # choose a random wpid end
kill_worker(sig, wpid)
click to toggle source
# File lib/rack-rabbit/server.rb, line 136 def kill_worker(sig, wpid) worker_pids.delete(wpid) killed_pids.push(wpid) Process.kill(sig, wpid) end
load_app()
click to toggle source
¶ ↑
RACK APP HANDLING
¶ ↑
# File lib/rack-rabbit/server.rb, line 250 def load_app inner_app, _options = RackRabbit.load_rack_app(config.rack_file) @app = Rack::Builder.new do use RackRabbit::Middleware::ProgramName run inner_app end.to_app logger.info "LOADED #{inner_app.name if inner_app.respond_to?(:name)} FROM #{config.rack_file}" @app end
maintain_worker_count()
click to toggle source
# File lib/rack-rabbit/server.rb, line 106 def maintain_worker_count unless shutting_down? diff = worker_pids.length - config.workers if diff > 0 diff.times { kill_random_worker(:QUIT) } elsif diff < 0 (-diff).times { spawn_worker } end end end
manage_workers()
click to toggle source
# File lib/rack-rabbit/server.rb, line 65 def manage_workers while true maintain_worker_count sig = signals.pop # BLOCKS until there is a signal case sig when :INT then shutdown(:INT) when :QUIT then shutdown(:QUIT) when :TERM then shutdown(:TERM) when :HUP reload when :CHLD reap_workers when :TTIN config.workers [config.max_workers, config.workers + 1].min when :TTOU config.workers [config.min_workers, config.workers - 1].max else raise RuntimeError, "unknown signal #{sig}" end end end
pid_status(pidfile)
click to toggle source
# File lib/rack-rabbit/server.rb, line 220 def pid_status(pidfile) return :exited unless File.exists?(pidfile) pid = ::File.read(pidfile).to_i return :dead if pid == 0 Process.kill(0, pid) :running rescue Errno::ESRCH :dead rescue Errno::EPERM :not_owned end
reap_workers()
click to toggle source
# File lib/rack-rabbit/server.rb, line 142 def reap_workers while true wpid = Process.waitpid(-1, Process::WNOHANG) return if wpid.nil? worker_pids.delete(wpid) killed_pids.delete(wpid) end rescue Errno::ECHILD end
redirect_output()
click to toggle source
# File lib/rack-rabbit/server.rb, line 179 def redirect_output if logfile = config.logfile logfile = File.expand_path(logfile) FileUtils.mkdir_p(File.dirname(logfile), :mode => 0755) FileUtils.touch logfile File.chmod(0644, logfile) $stderr.reopen(logfile, 'a') $stdout.reopen($stderr) $stdout.sync = $stderr.sync = true else $stderr.reopen('/dev/null', 'a') $stdout.reopen($stderr) end end
reload()
click to toggle source
# File lib/rack-rabbit/server.rb, line 99 def reload logger.info "RELOADING" config.reload load_app if config.preload_app kill_all_workers(:QUIT) # they will respawn automatically end
run()
click to toggle source
# File lib/rack-rabbit/server.rb, line 34 def run check_pid if config.daemonize daemonize elsif config.logfile redirect_output end write_pid logger.info "RUNNING #{config.app_id} (#{config.rack_file}) #{'DAEMONIZED' if config.daemonize}" logger.info " rabbit : #{config.rabbit}" logger.info " exchange : #{config.exchange} (#{config.exchange_type})" if config.exchange logger.info " queue : #{config.queue}" if config.queue logger.info " route : #{config.routing_key}" if config.routing_key logger.info " workers : #{config.workers}" logger.info " preload : true" if config.preload_app logger.info " logfile : #{config.logfile}" unless config.logfile.nil? logger.info " pidfile : #{config.pidfile}" unless config.pidfile.nil? load_app if config.preload_app trap_server_signals manage_workers end
shutdown(sig)
click to toggle source
# File lib/rack-rabbit/server.rb, line 154 def shutdown(sig) @shutting_down = true kill_all_workers(sig) Process.waitall logger.info "#{RackRabbit.friendly_signal(sig)} server" exit end
shutting_down?()
click to toggle source
# File lib/rack-rabbit/server.rb, line 162 def shutting_down? @shutting_down end
spawn_worker()
click to toggle source
# File lib/rack-rabbit/server.rb, line 117 def spawn_worker config.before_fork(self) worker_pids << fork do signals.close load_app unless config.preload_app worker = Worker.new(config, app) config.after_fork(self, worker) worker.run end end
trap_server_signals()
click to toggle source
write_pid()
click to toggle source
# File lib/rack-rabbit/server.rb, line 194 def write_pid pidfile = config.pidfile if pidfile begin File.open(pidfile, ::File::CREAT | ::File::EXCL | ::File::WRONLY){|f| f.write("#{Process.pid}") } at_exit { File.delete(pidfile) if File.exists?(pidfile) } rescue Errno::EEXIST check_pid retry end end end