serverengine 1.5.4 → 1.5.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +12 -0
- data/Changelog +11 -0
- data/lib/serverengine/embedded_server.rb +21 -3
- data/lib/serverengine/multi_process_server.rb +2 -1
- data/lib/serverengine/multi_thread_server.rb +14 -2
- data/lib/serverengine/process_manager.rb +90 -38
- data/lib/serverengine/supervisor.rb +1 -0
- data/lib/serverengine/version.rb +1 -1
- metadata +3 -2
data/.travis.yml
ADDED
data/Changelog
CHANGED
@@ -1,4 +1,15 @@
|
|
1
1
|
|
2
|
+
2013-09-17 version 1.5.5:
|
3
|
+
|
4
|
+
* worker_type=thread and embedded show uncaught errors caused in Worker#stop
|
5
|
+
and Worker#reload interface
|
6
|
+
* ProcessManager: enables child process heartbeat only if enable_heartbeat
|
7
|
+
option is true
|
8
|
+
* ProcessManager: doesn't call fcntl on pipe pairs if F_SETFD or FD_CLOEXEC
|
9
|
+
is not defined
|
10
|
+
* ProcessManager: added #spawn(*args) method
|
11
|
+
|
12
|
+
|
2
13
|
2013-09-10 version 1.5.4:
|
3
14
|
|
4
15
|
* SignalThread: fixed "Unexpected error can't be called from trap context"
|
@@ -27,19 +27,37 @@ module ServerEngine
|
|
27
27
|
|
28
28
|
def stop(stop_graceful)
|
29
29
|
super
|
30
|
-
Thread.new
|
30
|
+
Thread.new do
|
31
|
+
begin
|
32
|
+
@worker.stop
|
33
|
+
rescue => e
|
34
|
+
ServerEngine.dump_uncaught_error(e)
|
35
|
+
end
|
36
|
+
end
|
31
37
|
nil
|
32
38
|
end
|
33
39
|
|
34
40
|
def restart(stop_graceful)
|
35
41
|
super
|
36
|
-
Thread.new
|
42
|
+
Thread.new do
|
43
|
+
begin
|
44
|
+
@worker.stop
|
45
|
+
rescue => e
|
46
|
+
ServerEngine.dump_uncaught_error(e)
|
47
|
+
end
|
48
|
+
end
|
37
49
|
nil
|
38
50
|
end
|
39
51
|
|
40
52
|
def reload
|
41
53
|
super
|
42
|
-
Thread.new
|
54
|
+
Thread.new do
|
55
|
+
begin
|
56
|
+
@worker.reload
|
57
|
+
rescue => e
|
58
|
+
ServerEngine.dump_uncaught_error(e)
|
59
|
+
end
|
60
|
+
end
|
43
61
|
nil
|
44
62
|
end
|
45
63
|
end
|
@@ -23,6 +23,7 @@ module ServerEngine
|
|
23
23
|
auto_tick: false,
|
24
24
|
graceful_kill_signal: Daemon::Signals::GRACEFUL_STOP,
|
25
25
|
immediate_kill_signal: Daemon::Signals::IMMEDIATE_STOP,
|
26
|
+
enable_heartbeat: true,
|
26
27
|
auto_heartbeat: true,
|
27
28
|
on_heartbeat_error: Proc.new do
|
28
29
|
@logger.fatal "parent process unexpectedly terminated"
|
@@ -69,7 +70,7 @@ module ServerEngine
|
|
69
70
|
$0 = @worker_process_name % [wid] if @worker_process_name
|
70
71
|
w.install_signal_handlers
|
71
72
|
|
72
|
-
Daemon.change_privilege(@
|
73
|
+
Daemon.change_privilege(@chuser, @chgroup)
|
73
74
|
File.umask(@chumask) if @chumask
|
74
75
|
|
75
76
|
## recreate the logger created at Server#main
|
@@ -40,12 +40,24 @@ module ServerEngine
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def send_stop(stop_graceful)
|
43
|
-
Thread.new
|
43
|
+
Thread.new do
|
44
|
+
begin
|
45
|
+
@worker.stop
|
46
|
+
rescue => e
|
47
|
+
ServerEngine.dump_uncaught_error(e)
|
48
|
+
end
|
49
|
+
end
|
44
50
|
nil
|
45
51
|
end
|
46
52
|
|
47
53
|
def send_reload
|
48
|
-
Thread.new
|
54
|
+
Thread.new do
|
55
|
+
begin
|
56
|
+
@worker.reload
|
57
|
+
rescue => e
|
58
|
+
ServerEngine.dump_uncaught_error(e)
|
59
|
+
end
|
60
|
+
end
|
49
61
|
end
|
50
62
|
|
51
63
|
def join
|
@@ -31,9 +31,10 @@ module ServerEngine
|
|
31
31
|
@immediate_kill_signal = config[:immediate_kill_signal] || :QUIT
|
32
32
|
|
33
33
|
@auto_tick = config.fetch(:auto_tick, true)
|
34
|
-
@
|
34
|
+
@auto_tick_interval = config[:auto_tick_interval] || 1
|
35
35
|
|
36
|
-
@
|
36
|
+
@enable_heartbeat = !!config[:enable_heartbeat]
|
37
|
+
@auto_heartbeat = !!config.fetch(:auto_heartbeat, true)
|
37
38
|
|
38
39
|
case op = config[:on_heartbeat_error]
|
39
40
|
when nil
|
@@ -60,6 +61,10 @@ module ServerEngine
|
|
60
61
|
|
61
62
|
attr_accessor :cloexec_mode
|
62
63
|
|
64
|
+
attr_reader :graceful_kill_signal, :immediate_kill_signal
|
65
|
+
attr_reader :auto_tick, :auto_tick_interval
|
66
|
+
attr_reader :enable_heartbeat, :auto_heartbeat
|
67
|
+
|
63
68
|
CONFIG_PARAMS = {
|
64
69
|
heartbeat_interval: 1,
|
65
70
|
heartbeat_timeout: 180,
|
@@ -71,8 +76,6 @@ module ServerEngine
|
|
71
76
|
immediate_kill_timeout: 600,
|
72
77
|
}
|
73
78
|
|
74
|
-
attr_reader :graceful_kill_signal, :immediate_kill_signal
|
75
|
-
|
76
79
|
CONFIG_PARAMS.each_pair do |key,default_value|
|
77
80
|
attr_reader key
|
78
81
|
|
@@ -90,14 +93,14 @@ module ServerEngine
|
|
90
93
|
end
|
91
94
|
|
92
95
|
def fork(&block)
|
93
|
-
rpipe, wpipe =
|
96
|
+
rpipe, wpipe = new_pipe_pair
|
94
97
|
|
95
98
|
begin
|
96
99
|
pid = Process.fork do
|
97
100
|
self.close
|
98
101
|
begin
|
99
102
|
t = Target.new(wpipe)
|
100
|
-
if @auto_heartbeat
|
103
|
+
if @enable_heartbeat && @auto_heartbeat
|
101
104
|
HeartbeatThread.new(self, t, @heartbeat_error_proc)
|
102
105
|
end
|
103
106
|
|
@@ -115,25 +118,68 @@ module ServerEngine
|
|
115
118
|
|
116
119
|
@monitors << m
|
117
120
|
@rpipes[rpipe] = m
|
121
|
+
rpipe = nil
|
118
122
|
|
119
123
|
return m
|
120
124
|
|
121
125
|
ensure
|
122
126
|
wpipe.close
|
127
|
+
rpipe.close if rpipe
|
123
128
|
end
|
124
129
|
end
|
125
130
|
|
126
|
-
def
|
127
|
-
|
131
|
+
def spawn(*args)
|
132
|
+
if args.first.is_a?(Hash)
|
133
|
+
env = args.shift.dup
|
134
|
+
else
|
135
|
+
env = {}
|
136
|
+
end
|
128
137
|
|
129
|
-
|
130
|
-
|
131
|
-
wpipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
132
|
-
when :monitor_only
|
133
|
-
rpipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
138
|
+
if args.last.is_a?(Hash)
|
139
|
+
options = args.pop.dup
|
134
140
|
else
|
135
|
-
|
136
|
-
|
141
|
+
options = {}
|
142
|
+
end
|
143
|
+
|
144
|
+
# pipe is necessary even if @enable_heartbeat == false because
|
145
|
+
# parent process detects shutdown of a child process using it
|
146
|
+
rpipe, wpipe = new_pipe_pair
|
147
|
+
|
148
|
+
begin
|
149
|
+
options[wpipe.fileno] = wpipe
|
150
|
+
if @enable_heartbeat
|
151
|
+
env['SERVERENGINE_HEARTBEAT_PIPE'] = wpipe.fileno.to_s
|
152
|
+
end
|
153
|
+
|
154
|
+
pid = Process.spawn(env, *args, options)
|
155
|
+
|
156
|
+
m = Monitor.new(self, pid)
|
157
|
+
|
158
|
+
@monitors << m
|
159
|
+
@rpipes[rpipe] = m
|
160
|
+
rpipe = nil
|
161
|
+
|
162
|
+
return m
|
163
|
+
|
164
|
+
ensure
|
165
|
+
wpipe.close
|
166
|
+
rpipe.close if rpipe
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def new_pipe_pair
|
171
|
+
rpipe, wpipe = IO.pipe
|
172
|
+
|
173
|
+
if Fcntl.const_defined?(:F_SETFD) && Fcntl.const_defined?(:FD_CLOEXEC)
|
174
|
+
case @cloexec_mode
|
175
|
+
when :target_only
|
176
|
+
wpipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
177
|
+
when :monitor_only
|
178
|
+
rpipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
179
|
+
else
|
180
|
+
rpipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
181
|
+
wpipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
182
|
+
end
|
137
183
|
end
|
138
184
|
|
139
185
|
rpipe.sync = true
|
@@ -159,26 +205,25 @@ module ServerEngine
|
|
159
205
|
end
|
160
206
|
|
161
207
|
ready_pipes, _, _ = IO.select(@rpipes.keys, nil, nil, blocking_timeout)
|
162
|
-
unless ready_pipes
|
163
|
-
return nil
|
164
|
-
end
|
165
208
|
|
166
209
|
time ||= Time.now
|
167
210
|
|
168
|
-
ready_pipes
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
211
|
+
if ready_pipes
|
212
|
+
ready_pipes.each do |r|
|
213
|
+
begin
|
214
|
+
r.read_nonblock(1024, @read_buffer)
|
215
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
216
|
+
next
|
217
|
+
rescue #EOFError
|
218
|
+
m = @rpipes.delete(r)
|
219
|
+
m.start_immediate_stop!
|
220
|
+
r.close rescue nil
|
221
|
+
next
|
222
|
+
end
|
179
223
|
|
180
|
-
|
181
|
-
|
224
|
+
if m = @rpipes[r]
|
225
|
+
m.last_heartbeat_time = time
|
226
|
+
end
|
182
227
|
end
|
183
228
|
end
|
184
229
|
|
@@ -189,7 +234,7 @@ module ServerEngine
|
|
189
234
|
nil
|
190
235
|
end
|
191
236
|
|
192
|
-
def self.
|
237
|
+
def self.format_signal_name(n)
|
193
238
|
Signal.list.each_pair {|k,v|
|
194
239
|
return "SIG#{k}" if n == v
|
195
240
|
}
|
@@ -200,7 +245,7 @@ module ServerEngine
|
|
200
245
|
case code
|
201
246
|
when Process::Status
|
202
247
|
if code.signaled?
|
203
|
-
"signal #{
|
248
|
+
"signal #{format_signal_name(code.termsig)}"
|
204
249
|
else
|
205
250
|
"status #{code.exitstatus}"
|
206
251
|
end
|
@@ -301,10 +346,17 @@ module ServerEngine
|
|
301
346
|
return false unless pid
|
302
347
|
|
303
348
|
if !@immediate_kill_start_time
|
304
|
-
# check escalation
|
305
|
-
if
|
306
|
-
|
307
|
-
|
349
|
+
# check heartbeat timeout or escalation
|
350
|
+
if (
|
351
|
+
# heartbeat timeout
|
352
|
+
@pm.enable_heartbeat &&
|
353
|
+
heartbeat_delay >= @pm.heartbeat_timeout
|
354
|
+
) || (
|
355
|
+
# escalation
|
356
|
+
@graceful_kill_start_time &&
|
357
|
+
@pm.graceful_kill_timeout >= 0 &&
|
358
|
+
@graceful_kill_start_time < now - @pm.graceful_kill_timeout
|
359
|
+
)
|
308
360
|
# escalate to immediate kill
|
309
361
|
@kill_count = 0
|
310
362
|
@immediate_kill_start_time = now
|
@@ -362,7 +414,7 @@ module ServerEngine
|
|
362
414
|
|
363
415
|
def main
|
364
416
|
while true
|
365
|
-
@pm.tick(@pm.
|
417
|
+
@pm.tick(@pm.auto_tick_interval)
|
366
418
|
end
|
367
419
|
nil
|
368
420
|
rescue AlreadyClosedError
|
data/lib/serverengine/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serverengine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
12
|
+
date: 2013-09-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sigdump
|
@@ -67,6 +67,7 @@ extensions: []
|
|
67
67
|
extra_rdoc_files: []
|
68
68
|
files:
|
69
69
|
- .gitignore
|
70
|
+
- .travis.yml
|
70
71
|
- Changelog
|
71
72
|
- Gemfile
|
72
73
|
- LICENSE
|