1 # -*- encoding: binary -*-
6 # check if our Ruby implementation supports unlinked files
8 tmp = Unicorn::Util.tmpio
16 # we don't actually fork workers, but allow using the
17 # {before,after}_fork hooks found in Unicorn/Rainbows!
19 FORK_HOOK = lambda { |_,_| }
23 # runs the Rainbows! HttpServer with +app+ and +options+ and does
24 # not return until the server has exited.
25 def run(app, options = {})
26 HttpServer.new(app, options).start.join
30 class HttpServer < Rainbows::HttpServer
32 # only used if no concurrency model is specified
33 def worker_loop(worker)
34 init_worker_process(worker)
36 ret = IO.select(LISTENERS, nil, nil, nil) and
37 ret.first.each do |sock|
39 process_client(sock.accept_nonblock)
40 rescue Errno::EAGAIN, Errno::ECONNABORTED
44 rescue Errno::EBADF, TypeError
47 Rainbows::Error.listen_loop(e)
52 def maintain_worker_count; end
54 # can't just do a graceful exit if reopening logs fails, so we just
57 logger.info "reopening logs"
58 Unicorn::Util.reopen_logs
59 logger.info "done reopening logs"
61 logger.error "failed reopening logs #{e.message}"
66 trap(:INT) { stop(false) } # Mongrel trapped INT for Win32...
68 # try these anyways regardless of platform...
69 trap(:TERM) { stop(false) }
71 trap(:USR1) { reopen_logs }
72 trap(:USR2) { reexec }
74 # no other way to reliably switch concurrency models...
75 trap(:HUP) { reexec; stop }
77 # technically feasible in some cases, just not sanely supportable:
78 trap(:TTIN) { logger.info "SIGTTIN is not handled by Zbatery" }
79 trap(:TTOU) { logger.info "SIGTTOU is not handled by Zbatery" }
80 rescue => e # hopefully ignores errors on Win32...
81 logger.error "failed to setup signal handler: #{e.message}"
83 worker = Worker.new(0, $stdout)
84 before_fork.call(self, worker)
85 worker_loop(worker) # runs forever
88 def stop(graceful = true)
90 exit!(0) unless graceful
96 logger.warn "calling before_fork without forking"
103 logger.warn "calling after_fork without having forked"
110 # override stuff we don't need or can't use portably
114 # master == worker in our case
115 def init_worker_process(worker)
116 after_fork.call(self, worker)
117 build_app! unless preload_app
118 logger.info "Zbatery #@use worker_connections=#@worker_connections"
122 # we can't/don't need to do the fchmod heartbeat Unicorn/Rainbows! does
131 DEFAULTS[:before_fork] = DEFAULTS[:after_fork] = Zbatery::FORK_HOOK
134 unless Zbatery::UnlinkedIO
138 # Tempfiles should get automatically unlinked by GC
140 fp = Tempfile.new("zbatery")