1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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
62
63
64
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
| | # -*- encoding: binary -*-
# :enddoc:
require 'rainbows'
Rainbows.forked = true
module Zbatery
VERSION = "4.1.2"
Rainbows::Const::RACK_DEFAULTS["SERVER_SOFTWARE"] = "Zbatery #{VERSION}"
# we don't actually fork workers, but allow using the
# {before,after}_fork hooks found in Unicorn/Rainbows!
# config files...
FORK_HOOK = lambda { |_,_| }
end
# :stopdoc:
# override stuff we don't need or can't use portably
module Rainbows
module Base
# master == worker in our case
def init_worker_process(worker)
after_fork.call(self, worker)
worker.user(*user) if user.kind_of?(Array) && ! worker.switched
build_app! unless preload_app
Rainbows::Response.setup
Rainbows::MaxBody.setup
Rainbows::ProcessClient.const_set(:APP, @app)
logger.info "Zbatery #@use worker_connections=#@worker_connections"
end
end
# we can't/don't need to do the fchmod heartbeat Unicorn/Rainbows! does
def self.tick
alive
end
class HttpServer
# only used if no concurrency model is specified
def worker_loop(worker)
init_worker_process(worker)
begin
ret = IO.select(LISTENERS, nil, nil, nil) and
ret[0].each do |sock|
io = sock.kgio_tryaccept and process_client(io)
end
rescue Errno::EINTR
rescue Errno::EBADF, TypeError
break
rescue => e
Rainbows::Error.listen_loop(e)
end while Rainbows.alive
end
# no-op
def maintain_worker_count; end
def spawn_missing_workers; end
def init_self_pipe!; end
# can't just do a graceful exit if reopening logs fails, so we just
# continue on...
def reopen_logs
logger.info "reopening logs"
Unicorn::Util.reopen_logs
logger.info "done reopening logs"
rescue => e
logger.error "failed reopening logs #{e.message}"
end
def trap_deferred(sig)
# nothing
end
def join
at_exit { unlink_pid_safe(pid) if pid }
trap(:INT) { exit!(0) }
trap(:TERM) { exit!(0) }
trap(:QUIT) { Thread.new { stop } }
trap(:USR1) { Thread.new { reopen_logs } }
trap(:USR2) { Thread.new { reexec } }
trap(:HUP) { Thread.new { reexec; stop } }
trap(:CHLD, "DEFAULT")
# technically feasible in some cases, just not sanely supportable:
%w(TTIN TTOU WINCH).each do |sig|
trap(sig) do
Thread.new { logger.info("SIG#{sig} is not handled by Zbatery") }
end
end
if ready_pipe
ready_pipe.syswrite($$.to_s)
ready_pipe.close
self.ready_pipe = nil
end
extend(Rainbows.const_get(@use))
worker = Worker.new(0)
before_fork.call(self, worker)
worker_loop(worker) # runs forever
end
def stop(graceful = true)
Rainbows.quit!
graceful ? exit : exit!(0)
end
def before_fork
hook = super
hook == Zbatery::FORK_HOOK or
logger.warn "calling before_fork without forking"
hook
end
def after_fork
hook = super
hook == Zbatery::FORK_HOOK or
logger.warn "calling after_fork without having forked"
hook
end
end
end
Unicorn::Configurator::DEFAULTS[:before_fork] =
Unicorn::Configurator::DEFAULTS[:after_fork] = Zbatery::FORK_HOOK
|