1 # -*- encoding: binary -*-
6 # current version of Zbatery
11 # runs the Zbatery HttpServer with +app+ and +options+ and does
12 # not return until the server has exited.
13 def run(app, options = {})
14 HttpServer.new(app, options).start.join
18 Rainbows::Const::RACK_DEFAULTS["SERVER_SOFTWARE"] = "Zbatery #{VERSION}"
20 # true if our Ruby implementation supports unlinked files
22 tmp = Unicorn::Util.tmpio
30 # we don't actually fork workers, but allow using the
31 # {before,after}_fork hooks found in Unicorn/Rainbows!
33 FORK_HOOK = lambda { |_,_| }
35 class HttpServer < Rainbows::HttpServer
37 # this class is only used to avoid breaking Unicorn user switching
42 # only used if no concurrency model is specified
43 def worker_loop(worker)
44 init_worker_process(worker)
46 ret = IO.select(LISTENERS, nil, nil, nil) and
47 ret.first.each do |sock|
49 process_client(sock.accept_nonblock)
50 rescue Errno::EAGAIN, Errno::ECONNABORTED
54 rescue Errno::EBADF, TypeError
57 Rainbows::Error.listen_loop(e)
62 def maintain_worker_count; end
64 # can't just do a graceful exit if reopening logs fails, so we just
67 logger.info "reopening logs"
68 Unicorn::Util.reopen_logs
69 logger.info "done reopening logs"
71 logger.error "failed reopening logs #{e.message}"
76 trap(:INT) { stop(false) } # Mongrel trapped INT for Win32...
78 # try these anyways regardless of platform...
79 trap(:TERM) { stop(false) }
81 trap(:USR1) { reopen_logs }
82 trap(:USR2) { reexec }
84 # no other way to reliably switch concurrency models...
85 trap(:HUP) { reexec; stop }
87 # technically feasible in some cases, just not sanely supportable:
88 %w(TTIN TTOU WINCH).each do |sig|
89 trap(sig) { logger.info "SIG#{sig} is not handled by Zbatery" }
91 rescue => e # hopefully ignores errors on Win32...
92 logger.error "failed to setup signal handler: #{e.message}"
94 worker = Worker.new(0, DeadIO.new)
95 before_fork.call(self, worker)
96 worker_loop(worker) # runs forever
99 def stop(graceful = true)
101 exit!(0) unless graceful
107 logger.warn "calling before_fork without forking"
114 logger.warn "calling after_fork without having forked"
121 # override stuff we don't need or can't use portably
125 # master == worker in our case
126 def init_worker_process(worker)
127 after_fork.call(self, worker)
128 build_app! unless preload_app
129 logger.info "Zbatery #@use worker_connections=#@worker_connections"
133 # we can't/don't need to do the fchmod heartbeat Unicorn/Rainbows! does
142 DEFAULTS[:before_fork] = DEFAULTS[:after_fork] = Zbatery::FORK_HOOK
145 unless Zbatery::UnlinkedIO
149 # Tempfiles should get automatically unlinked by GC
151 fp = Tempfile.new("zbatery")