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
128
129
130
131
132
| | # -*- encoding: binary -*-
# :enddoc:
require 'rainbows'
Rainbows.forked = true
module Zbatery
VERSION = "4.2.0"
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
@readers = [] # rainbows 4.6.x compatibility
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
begin
ready_pipe.syswrite($$.to_s)
rescue => e
logger.warn("grandparent died too soon?: #{e.message} (#{e.class})")
end
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
|