serverengine 1.5.4 → 1.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|