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 ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - rbx-19mode
7
+
8
+ branches:
9
+ only:
10
+ - master
11
+
12
+ script: bundle exec rake
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 { @worker.stop }
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 { @worker.stop }
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 { @worker.reload }
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(@chumask, @chgroup)
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 { @worker.stop }
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 { @worker.reload }
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
- @tick_interval = config[:tick_interval] || 1
34
+ @auto_tick_interval = config[:auto_tick_interval] || 1
35
35
 
36
- @auto_heartbeat = config.fetch(:auto_heartbeat, true)
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 = new_pair
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 new_pair
127
- rpipe, wpipe = IO.pipe
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
- case @cloexec_mode
130
- when :target_only
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
- rpipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
136
- wpipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
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.each do |r|
169
- begin
170
- r.read_nonblock(1024, @read_buffer)
171
- rescue Errno::EAGAIN, Errno::EINTR
172
- next
173
- rescue #EOFError
174
- m = @rpipes.delete(r)
175
- m.start_immediate_stop!
176
- r.close rescue nil
177
- next
178
- end
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
- if m = @rpipes[r]
181
- m.last_heartbeat_time = time
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.signal_name(n)
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 #{signal_name(code.termsig)}"
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 heartbeat_delay >= @pm.heartbeat_timeout ||
306
- (@graceful_kill_start_time && @pm.graceful_kill_timeout >= 0 &&
307
- @graceful_kill_start_time < now - @pm.graceful_kill_timeout)
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.tick_interval)
417
+ @pm.tick(@pm.auto_tick_interval)
366
418
  end
367
419
  nil
368
420
  rescue AlreadyClosedError
@@ -31,6 +31,7 @@ module ServerEngine
31
31
  auto_tick: false,
32
32
  graceful_kill_signal: Daemon::Signals::GRACEFUL_STOP,
33
33
  immediate_kill_signal: Daemon::Signals::IMMEDIATE_STOP,
34
+ enable_heartbeat: true,
34
35
  auto_heartbeat: true,
35
36
  )
36
37
 
@@ -1,3 +1,3 @@
1
1
  module ServerEngine
2
- VERSION = "1.5.4"
2
+ VERSION = "1.5.5"
3
3
  end
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
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-10 00:00:00.000000000 Z
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