Class: RackRabbit::Server
- Inherits:
-
Object
- Object
- RackRabbit::Server
- Defined in:
- lib/rack-rabbit/server.rb
Instance Attribute Summary collapse
-
#app ⇒ Object
readonly
————————————————————————–.
-
#config ⇒ Object
readonly
————————————————————————–.
-
#killed_pids ⇒ Object
readonly
————————————————————————–.
-
#logger ⇒ Object
readonly
————————————————————————–.
-
#server_pid ⇒ Object
readonly
————————————————————————–.
-
#signals ⇒ Object
readonly
————————————————————————–.
-
#worker_pids ⇒ Object
readonly
————————————————————————–.
Instance Method Summary collapse
- #check_pid ⇒ Object
-
#daemonize ⇒ Object
DAEMONIZING, PID MANAGEMENT, and OUTPUT REDIRECTION ==========================================================================.
-
#initialize(options) ⇒ Server
constructor
A new instance of Server.
- #kill_all_workers(sig) ⇒ Object
- #kill_random_worker(sig) ⇒ Object
- #kill_worker(sig, wpid) ⇒ Object
-
#load_app ⇒ Object
RACK APP HANDLING ==========================================================================.
- #maintain_worker_count ⇒ Object
-
#manage_workers ⇒ Object
————————————————————————–.
- #pid_status(pidfile) ⇒ Object
- #reap_workers ⇒ Object
- #redirect_output ⇒ Object
-
#reload ⇒ Object
————————————————————————–.
-
#run ⇒ Object
————————————————————————–.
-
#shutdown(sig) ⇒ Object
————————————————————————–.
- #shutting_down? ⇒ Boolean
- #spawn_worker ⇒ Object
-
#trap_server_signals ⇒ Object
SIGNAL HANDLING ==========================================================================.
- #write_pid ⇒ Object
Constructor Details
Instance Attribute Details
#app ⇒ Object (readonly)
15 16 17 |
# File 'lib/rack-rabbit/server.rb', line 15 def app @app end |
#config ⇒ Object (readonly)
15 16 17 |
# File 'lib/rack-rabbit/server.rb', line 15 def config @config end |
#killed_pids ⇒ Object (readonly)
15 16 17 |
# File 'lib/rack-rabbit/server.rb', line 15 def killed_pids @killed_pids end |
#logger ⇒ Object (readonly)
15 16 17 |
# File 'lib/rack-rabbit/server.rb', line 15 def logger @logger end |
#server_pid ⇒ Object (readonly)
15 16 17 |
# File 'lib/rack-rabbit/server.rb', line 15 def server_pid @server_pid end |
#signals ⇒ Object (readonly)
15 16 17 |
# File 'lib/rack-rabbit/server.rb', line 15 def signals @signals end |
#worker_pids ⇒ Object (readonly)
15 16 17 |
# File 'lib/rack-rabbit/server.rb', line 15 def worker_pids @worker_pids end |
Instance Method Details
#check_pid ⇒ Object
207 208 209 210 211 212 213 214 215 216 217 218 |
# 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 ⇒ Object
DAEMONIZING, PID MANAGEMENT, and OUTPUT REDIRECTION
170 171 172 173 174 175 176 177 |
# 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) ⇒ Object
132 133 134 |
# 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) ⇒ Object
128 129 130 |
# 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) ⇒ Object
136 137 138 139 140 |
# 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 ⇒ Object
RACK APP HANDLING
250 251 252 253 254 255 256 257 258 |
# File 'lib/rack-rabbit/server.rb', line 250 def load_app inner_app, = 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 ⇒ Object
106 107 108 109 110 111 112 113 114 115 |
# 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 ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# 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) ⇒ Object
220 221 222 223 224 225 226 227 228 229 230 |
# 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 ⇒ Object
142 143 144 145 146 147 148 149 150 |
# 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 ⇒ Object
179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/rack-rabbit/server.rb', line 179 def redirect_output if logfile = config.logfile logfile = File.(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 ⇒ Object
99 100 101 102 103 104 |
# 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 ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# 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) ⇒ Object
154 155 156 157 158 159 160 |
# 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? ⇒ Boolean
162 163 164 |
# File 'lib/rack-rabbit/server.rb', line 162 def shutting_down? @shutting_down end |
#spawn_worker ⇒ Object
117 118 119 120 121 122 123 124 125 126 |
# 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 ⇒ Object
SIGNAL HANDLING
236 237 238 239 240 241 242 243 244 |
# File 'lib/rack-rabbit/server.rb', line 236 def trap_server_signals [:HUP, :INT, :QUIT, :TERM, :CHLD, :TTIN, :TTOU].each do |sig| trap(sig) do signals.push(sig) end end end |
#write_pid ⇒ Object
194 195 196 197 198 199 200 201 202 203 204 205 |
# 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 |