1 # -*- encoding: binary -*-
9 Rainbows::Const::RACK_DEFAULTS["SERVER_SOFTWARE"] = "Zbatery #{VERSION}"
11 # we don't actually fork workers, but allow using the
12 # {before,after}_fork hooks found in Unicorn/Rainbows!
14 FORK_HOOK = lambda { |_,_| }
18 # override stuff we don't need or can't use portably
20 @readers = [] # rainbows 4.6.x compatibility
23 # master == worker in our case
24 def init_worker_process(worker)
25 after_fork.call(self, worker)
26 worker.user(*user) if user.kind_of?(Array) && ! worker.switched
27 build_app! unless preload_app
28 Rainbows::Response.setup
29 Rainbows::MaxBody.setup
30 Rainbows::ProcessClient.const_set(:APP, @app)
32 logger.info "Zbatery #@use worker_connections=#@worker_connections"
36 # we can't/don't need to do the fchmod heartbeat Unicorn/Rainbows! does
43 # only used if no concurrency model is specified
44 def worker_loop(worker)
45 init_worker_process(worker)
47 ret = IO.select(LISTENERS, nil, nil, nil) and
49 io = sock.kgio_tryaccept and process_client(io)
52 rescue Errno::EBADF, TypeError
55 Rainbows::Error.listen_loop(e)
56 end while Rainbows.alive
60 def maintain_worker_count; end
61 def spawn_missing_workers; end
62 def init_self_pipe!; 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}"
74 def trap_deferred(sig)
79 at_exit { unlink_pid_safe(pid) if pid }
80 trap(:INT) { exit!(0) }
81 trap(:TERM) { exit!(0) }
82 trap(:QUIT) { Thread.new { stop } }
83 trap(:USR1) { Thread.new { reopen_logs } }
84 trap(:USR2) { Thread.new { reexec } }
85 trap(:HUP) { Thread.new { reexec; stop } }
86 trap(:CHLD, "DEFAULT")
88 # technically feasible in some cases, just not sanely supportable:
89 %w(TTIN TTOU WINCH).each do |sig|
91 Thread.new { logger.info("SIG#{sig} is not handled by Zbatery") }
97 ready_pipe.syswrite($$.to_s)
99 logger.warn("grandparent died too soon?: #{e.message} (#{e.class})")
102 self.ready_pipe = nil
104 extend(Rainbows.const_get(@use))
105 worker = Worker.new(0)
106 before_fork.call(self, worker)
107 worker_loop(worker) # runs forever
110 def stop(graceful = true)
112 graceful ? exit : exit!(0)
117 hook == Zbatery::FORK_HOOK or
118 logger.warn "calling before_fork without forking"
124 hook == Zbatery::FORK_HOOK or
125 logger.warn "calling after_fork without having forked"
131 Unicorn::Configurator::DEFAULTS[:before_fork] =
132 Unicorn::Configurator::DEFAULTS[:after_fork] = Zbatery::FORK_HOOK