parallel_server 0.1.5.1 → 0.1.6
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.
- checksums.yaml +4 -4
- data/README.md +13 -0
- data/lib/parallel_server/prefork.rb +75 -17
- data/test/parallel_server/test_prefork.rb +392 -0
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2e68bf1d6ac3906be2d5cc6fd0a4cf06fd2f6a77
|
4
|
+
data.tar.gz: d6b0f09154ec046e08353bdf7660941e7395a308
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97eb5ecec4518b6c0f20e0c3d13f93610ae475f53731d63d5397aa5d36bacd973009980c69614036409b6a2efadbf455fbf2b88658fef75fb23670dd5a6fc509
|
7
|
+
data.tar.gz: a83190db61bfad2f2cac203851fb5022ec0c83dced8d50798eeb368dfb24c36fa37bb39c96fb808d68519cabb6d96c5a88f0b97ac182d7c9b41ccdf12f666429
|
data/README.md
CHANGED
@@ -68,6 +68,13 @@ max_idle 経過後でもクライアントと接続中であればプロセス
|
|
68
68
|
クライアントがこの回数の接続を受け付けるとプロセスを終了します(デフォルト: 1000)。
|
69
69
|
max_use 経過後でもクライアントと接続中であればプロセスは終了しません。ただし `:min_processes`, `:max_processes` のカウント対象外です。
|
70
70
|
|
71
|
+
`:watchdog_timer` :
|
72
|
+
子プロセスからのハートビートがこの秒数以上途切れると該当子プロセスに SIGTERM を送ります(デフォルト: 600)。
|
73
|
+
その後も子プロセスが死なない場合は60秒後に SIGKILL を送ります。
|
74
|
+
|
75
|
+
`:watchdog_signal` :
|
76
|
+
`:watchdog_timer` が切れた時に子プロセスに送るシグナルを文字列で指定します(デフォルト: `TERM`)。
|
77
|
+
|
71
78
|
`:on_start` :
|
72
79
|
子プロセス起動時に*子プロセス側*で実行される処理を Proc で指定します。Proc 実行時の引数はありません。
|
73
80
|
|
@@ -107,3 +114,9 @@ start を終了します。クライアントと接続中の子プロセスは
|
|
107
114
|
* `stop!`
|
108
115
|
|
109
116
|
start を終了します。子プロセスがクライアントと接続中でも SIGTERM で終了させます。
|
117
|
+
|
118
|
+
### #detach_children
|
119
|
+
|
120
|
+
* `detach_children`
|
121
|
+
|
122
|
+
子プロセスを切り離します。子プロセスは待ち受けポートを閉じ、接続中のクライアントがいなくなると終了します。
|
@@ -9,6 +9,8 @@ module ParallelServer
|
|
9
9
|
DEFAULT_STANDBY_THREADS = 5
|
10
10
|
DEFAULT_MAX_IDLE = 10
|
11
11
|
DEFAULT_MAX_USE = 1000
|
12
|
+
DEFAULT_WATCHDOG_TIMER = 600
|
13
|
+
DEFAULT_WATCHDOG_SIGNAL = 'TERM'
|
12
14
|
|
13
15
|
attr_reader :child_status
|
14
16
|
|
@@ -21,6 +23,8 @@ module ParallelServer
|
|
21
23
|
# @option opts [Integer] :max_threads (1) maximum threads per process
|
22
24
|
# @option opts [Integer] :standby_threads (5) keep free processes or threads
|
23
25
|
# @option opts [Integer] :listen_backlog (nil) listen backlog
|
26
|
+
# @option opts [Integer] :watchdog_timer (600) watchdog timer
|
27
|
+
# @option opts [Integer] :watchdog_signal ('TERM') this signal is sent when watchdog timer expired.
|
24
28
|
# @option opts [#call] :on_start (nil) object#call() is invoked when child process start. This is called in child process.
|
25
29
|
# @option opts [#call] :on_reload (nil) object#call(hash) is invoked when reload. This is called in child process.
|
26
30
|
# @option opts [#call] :on_child_start (nil) object#call(pid) is invoked when child process exit. This is call in parent process.
|
@@ -56,8 +60,7 @@ module ParallelServer
|
|
56
60
|
raise 'block required' unless block
|
57
61
|
@block = block
|
58
62
|
unless @sockets
|
59
|
-
@sockets =
|
60
|
-
@sockets.each{|s| s.listen(@listen_backlog)} if @listen_backlog
|
63
|
+
@sockets = create_server_socket(@host, @port, @listen_backlog)
|
61
64
|
@sockets_created = true
|
62
65
|
end
|
63
66
|
@reload_args = nil
|
@@ -99,6 +102,15 @@ module ParallelServer
|
|
99
102
|
@loop = false
|
100
103
|
end
|
101
104
|
|
105
|
+
# @return [void]
|
106
|
+
def detach_children
|
107
|
+
t = Time.now + 5
|
108
|
+
talk_to_children(detach: true)
|
109
|
+
while Time.now < t && @child_status.values.any?{|s| s[:status] == :run}
|
110
|
+
watch_children
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
102
114
|
private
|
103
115
|
|
104
116
|
# @return [void]
|
@@ -108,30 +120,43 @@ module ParallelServer
|
|
108
120
|
old_listen_backlog = @listen_backlog
|
109
121
|
set_variables_from_opts
|
110
122
|
|
111
|
-
address_changed = false
|
112
123
|
if @sockets_created ? (@host != host || @port != port) : @sockets != sockets
|
113
124
|
@sockets.each{|s| s.close rescue nil} if @sockets_created
|
125
|
+
detach_children
|
114
126
|
@sockets, @host, @port = sockets, host, port
|
115
127
|
if @sockets
|
116
128
|
@sockets_created = false
|
117
129
|
else
|
118
|
-
@sockets =
|
119
|
-
@sockets.each{|s| s.listen(@listen_backlog)} if @listen_backlog
|
130
|
+
@sockets = create_server_socket(@host, @port, @listen_backlog)
|
120
131
|
@sockets_created = true
|
121
132
|
end
|
122
|
-
address_changed = true
|
123
133
|
elsif @listen_backlog != old_listen_backlog
|
124
134
|
@sockets.each{|s| s.listen(@listen_backlog)} if @listen_backlog && @sockets_created
|
125
135
|
end
|
126
136
|
|
127
|
-
reload_children
|
137
|
+
reload_children
|
138
|
+
end
|
139
|
+
|
140
|
+
# @param host [String] hostname or IP address
|
141
|
+
# @param port [Integer / String] port number / service name
|
142
|
+
# @param backlog [Integer / nil] listen backlog
|
143
|
+
# @return [Array<Socket>] listening sockets
|
144
|
+
def create_server_socket(host, port, backlog)
|
145
|
+
t = Time.now + 5
|
146
|
+
begin
|
147
|
+
sockets = Socket.tcp_server_sockets(host, port)
|
148
|
+
rescue Errno::EADDRINUSE
|
149
|
+
raise if Time.now > t
|
150
|
+
sleep 0.1
|
151
|
+
retry
|
152
|
+
end
|
153
|
+
sockets.each{|s| s.listen(backlog)} if backlog
|
154
|
+
sockets
|
128
155
|
end
|
129
156
|
|
130
|
-
# @param address_changed [true/false]
|
131
157
|
# @return [void]
|
132
|
-
def reload_children
|
158
|
+
def reload_children
|
133
159
|
data = {}
|
134
|
-
data[:address_changed] = address_changed
|
135
160
|
data[:options] = @opts.select{|_, value| Marshal.dump(value) rescue nil}
|
136
161
|
talk_to_children data
|
137
162
|
end
|
@@ -204,6 +229,7 @@ module ParallelServer
|
|
204
229
|
if readable
|
205
230
|
readable.each do |from_child|
|
206
231
|
if st = Conversation.recv(from_child)
|
232
|
+
st[:time] = Time.now
|
207
233
|
@child_status[from_child].update st
|
208
234
|
if st[:status] == :stop
|
209
235
|
@to_child[from_child].close rescue nil
|
@@ -218,6 +244,7 @@ module ParallelServer
|
|
218
244
|
end
|
219
245
|
end
|
220
246
|
end
|
247
|
+
kill_frozen_children
|
221
248
|
if @children.size != @child_status.size
|
222
249
|
wait_children
|
223
250
|
end
|
@@ -250,6 +277,19 @@ module ParallelServer
|
|
250
277
|
@child_status.values.count{|st| st[:status] == :run}
|
251
278
|
end
|
252
279
|
|
280
|
+
# @return [void]
|
281
|
+
def kill_frozen_children
|
282
|
+
now = Time.now
|
283
|
+
@child_status.each do |r, st|
|
284
|
+
if now > st[:time] + @watchdog_timer + 60
|
285
|
+
Process.kill 'KILL', @from_child[r]
|
286
|
+
elsif now > st[:time] + @watchdog_timer && ! st[:signal_sent]
|
287
|
+
Process.kill @watchdog_signal, @from_child[r]
|
288
|
+
st[:signal_sent] = true
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
253
293
|
# @return [void]
|
254
294
|
def wait_children
|
255
295
|
@children.delete_if do |pid|
|
@@ -284,7 +324,7 @@ module ParallelServer
|
|
284
324
|
r, w = from_child[0], to_child[1]
|
285
325
|
@from_child[r] = pid
|
286
326
|
@to_child[r] = w
|
287
|
-
@child_status[r] = {status: :run, connections: {}}
|
327
|
+
@child_status[r] = {status: :run, connections: {}, time: Time.now}
|
288
328
|
@children.push pid
|
289
329
|
@on_child_start.call(pid) if @on_child_start
|
290
330
|
end
|
@@ -295,6 +335,8 @@ module ParallelServer
|
|
295
335
|
@max_threads = @opts[:max_threads] || DEFAULT_MAX_THREADS
|
296
336
|
@standby_threads = @opts[:standby_threads] || DEFAULT_STANDBY_THREADS
|
297
337
|
@listen_backlog = @opts[:listen_backlog]
|
338
|
+
@watchdog_timer = @opts[:watchdog_timer] || DEFAULT_WATCHDOG_TIMER
|
339
|
+
@watchdog_signal = @opts[:watchdog_signal] || DEFAULT_WATCHDOG_SIGNAL
|
298
340
|
@on_start = @opts[:on_start]
|
299
341
|
@on_child_start = @opts[:on_child_start]
|
300
342
|
@on_child_exit = @opts[:on_child_exit]
|
@@ -373,6 +415,9 @@ module ParallelServer
|
|
373
415
|
count += 1
|
374
416
|
break if max_use > 0 && count >= max_use
|
375
417
|
end
|
418
|
+
rescue => e
|
419
|
+
STDERR.puts e.inspect, e.backtrace.inspect
|
420
|
+
raise e
|
376
421
|
ensure
|
377
422
|
@status = :stop
|
378
423
|
queue.push true
|
@@ -389,16 +434,29 @@ module ParallelServer
|
|
389
434
|
# @param queue [Queue]
|
390
435
|
# @return [void]
|
391
436
|
def reload_loop(queue)
|
437
|
+
heartbeat_interval = 5
|
392
438
|
while true
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
439
|
+
time = Time.now
|
440
|
+
if IO.select([@from_parent], nil, nil, heartbeat_interval)
|
441
|
+
heartbeat_interval -= Time.now - time
|
442
|
+
heartbeat_interval = 0 if heartbeat_interval < 0
|
443
|
+
data = Conversation.recv(@from_parent)
|
444
|
+
break if data.nil? or data[:detach]
|
445
|
+
@options.update data[:options] if data[:options]
|
446
|
+
@options[:on_reload].call @options if @options[:on_reload]
|
447
|
+
@threads_cv.signal
|
448
|
+
else
|
449
|
+
heartbeat_interval = 5
|
450
|
+
@threads_mutex.synchronize do
|
451
|
+
Conversation.send(@to_parent, {})
|
452
|
+
end
|
453
|
+
end
|
399
454
|
end
|
400
455
|
@from_parent.close
|
401
456
|
@from_parent = nil
|
457
|
+
rescue => e
|
458
|
+
STDERR.puts e.inspect, e.backtrace.inspect
|
459
|
+
raise e
|
402
460
|
ensure
|
403
461
|
@status = :stop
|
404
462
|
queue.push true
|
@@ -0,0 +1,392 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/notify'
|
3
|
+
require 'socket'
|
4
|
+
require 'timeout'
|
5
|
+
require 'tempfile'
|
6
|
+
|
7
|
+
require 'parallel_server/prefork'
|
8
|
+
|
9
|
+
class TestParallelServerPrefork < Test::Unit::TestCase
|
10
|
+
def setup
|
11
|
+
@tmpf = Tempfile.new('test_prefork')
|
12
|
+
@prefork = ParallelServer::Prefork.new(*args, opts)
|
13
|
+
@thr = Thread.new do
|
14
|
+
begin
|
15
|
+
@prefork.start do |sock|
|
16
|
+
begin
|
17
|
+
sock.puts $$.to_s
|
18
|
+
sock.gets
|
19
|
+
rescue Errno::EPIPE
|
20
|
+
end
|
21
|
+
end
|
22
|
+
rescue
|
23
|
+
p $!, $@
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
end
|
27
|
+
sleep 1
|
28
|
+
@clients = []
|
29
|
+
end
|
30
|
+
|
31
|
+
def teardown
|
32
|
+
@clients.each do |c|
|
33
|
+
c.close rescue nil
|
34
|
+
end
|
35
|
+
@prefork.stop!
|
36
|
+
@thr.join rescue nil
|
37
|
+
@tmpf.close true
|
38
|
+
end
|
39
|
+
|
40
|
+
def args
|
41
|
+
[port]
|
42
|
+
end
|
43
|
+
|
44
|
+
def port
|
45
|
+
ENV['TEST_PORT'] || 12345
|
46
|
+
end
|
47
|
+
|
48
|
+
def connect
|
49
|
+
s = TCPSocket.new('localhost', port)
|
50
|
+
@clients.push s
|
51
|
+
s.gets
|
52
|
+
s
|
53
|
+
end
|
54
|
+
|
55
|
+
def opts
|
56
|
+
{}
|
57
|
+
end
|
58
|
+
|
59
|
+
sub_test_case 'max_process: 1, max_threads: 1' do
|
60
|
+
def opts
|
61
|
+
{
|
62
|
+
min_processes: 1,
|
63
|
+
max_processes: 1,
|
64
|
+
max_threads: 1,
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
test '2nd wait for connection' do
|
69
|
+
connect
|
70
|
+
assert_raise Timeout::Error do
|
71
|
+
Timeout.timeout(0.5){ connect }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
test '2nd connect after 1st connection is closed' do
|
76
|
+
connect
|
77
|
+
Thread.new{ sleep 0.3; @clients.first.puts }
|
78
|
+
Timeout.timeout(1){ connect }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
sub_test_case 'max_process: 1, max_threads: 3' do
|
83
|
+
def opts
|
84
|
+
{
|
85
|
+
min_processes: 1,
|
86
|
+
max_processes: 1,
|
87
|
+
max_threads: 3,
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
test '4th request wait for connection' do
|
92
|
+
3.times{ connect }
|
93
|
+
assert_raise Timeout::Error do
|
94
|
+
Timeout.timeout(0.5){ connect }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
test '4th connect after 1st connection is closed' do
|
99
|
+
3.times{ connect }
|
100
|
+
Thread.new{ sleep 0.3; @clients.first.puts }
|
101
|
+
Timeout.timeout(1){ connect }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
sub_test_case 'max_process: 3, max_threads: 1' do
|
106
|
+
def opts
|
107
|
+
{
|
108
|
+
min_processes: 1,
|
109
|
+
max_processes: 3,
|
110
|
+
max_threads: 1,
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
test '4th request wait for connection' do
|
115
|
+
3.times{ connect }
|
116
|
+
assert_raise Timeout::Error do
|
117
|
+
Timeout.timeout(0.5){ connect }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
test '4th connect after 1st connection is closed' do
|
122
|
+
3.times{ connect }
|
123
|
+
Thread.new{ sleep 0.3; @clients.first.puts }
|
124
|
+
Timeout.timeout(1){ connect }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
sub_test_case 'min_processes: 3' do
|
129
|
+
def opts
|
130
|
+
{
|
131
|
+
min_processes: 3,
|
132
|
+
standby_threads: 1,
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
test '3 child processes exist' do
|
137
|
+
c = Dir.glob('/proc/*/status').count do |stat|
|
138
|
+
File.read(stat) =~ /^PPid:\t#{$$}$/
|
139
|
+
end
|
140
|
+
assert_equal 3, c
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
sub_test_case 'max_idle' do
|
145
|
+
def opts
|
146
|
+
@children = []
|
147
|
+
{
|
148
|
+
min_processes: 1,
|
149
|
+
max_processes: 1,
|
150
|
+
max_idle: 0.1,
|
151
|
+
on_child_start: ->(pid){ @children.push pid },
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
test 'unconnected process exists even if max_idle expired' do
|
156
|
+
sleep 0.5
|
157
|
+
assert File.exist?("/proc/#{@children[0]}")
|
158
|
+
assert_equal 1, @children.size
|
159
|
+
end
|
160
|
+
|
161
|
+
test 'first child process exited if it is connected' do
|
162
|
+
Process.waitpid fork{ connect.close }
|
163
|
+
sleep 0.5
|
164
|
+
assert ! File.exist?("/proc/#{@children[0]}")
|
165
|
+
assert_equal 2, @children.size
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
sub_test_case 'max_use' do
|
170
|
+
def opts
|
171
|
+
@children = []
|
172
|
+
{
|
173
|
+
min_processes: 1,
|
174
|
+
max_processes: 1,
|
175
|
+
max_use: 2,
|
176
|
+
on_child_start: ->(pid){ @children.push pid },
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
test 'child process exited if it is connected max_use times' do
|
181
|
+
Process.waitpid fork{ connect.close }
|
182
|
+
sleep 0.5
|
183
|
+
assert File.exist?("/proc/#{@children[0]}")
|
184
|
+
Process.waitpid fork{ connect.close }
|
185
|
+
sleep 0.5
|
186
|
+
assert ! File.exist?("/proc/#{@children[0]}")
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
sub_test_case 'standby_threads' do
|
191
|
+
def opts
|
192
|
+
@children = []
|
193
|
+
{
|
194
|
+
min_processes: 1,
|
195
|
+
max_processes: 20,
|
196
|
+
max_threads: 2,
|
197
|
+
on_child_start: ->(pid){ @children.push pid }
|
198
|
+
}
|
199
|
+
end
|
200
|
+
|
201
|
+
sub_test_case 'standby_threads=1' do
|
202
|
+
def opts
|
203
|
+
{
|
204
|
+
standby_threads: 1
|
205
|
+
}.merge super
|
206
|
+
end
|
207
|
+
|
208
|
+
test '1 child start' do
|
209
|
+
assert_equal 1, @children.size
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
sub_test_case '1 < standby_threads <= max_processes/max_threads' do
|
214
|
+
def opts
|
215
|
+
{
|
216
|
+
standby_threads: 10
|
217
|
+
}.merge super
|
218
|
+
end
|
219
|
+
|
220
|
+
test 'n children start' do
|
221
|
+
assert_equal 5, @children.size
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
sub_test_case 'standby_threads > max_processes/max_threads' do
|
226
|
+
def opts
|
227
|
+
{
|
228
|
+
standby_threads: 100
|
229
|
+
}.merge super
|
230
|
+
end
|
231
|
+
|
232
|
+
test 'max_processes children start' do
|
233
|
+
assert_equal 20, @children.size
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
sub_test_case 'on_start' do
|
239
|
+
def opts
|
240
|
+
{
|
241
|
+
min_processes: 1,
|
242
|
+
max_processes: 2,
|
243
|
+
max_threads: 1,
|
244
|
+
standby_threads: 1,
|
245
|
+
on_start: ->(){ File.open(@tmpf.path, 'a'){|f| f.puts $$} },
|
246
|
+
}
|
247
|
+
end
|
248
|
+
|
249
|
+
test 'execute block in child process when child start' do
|
250
|
+
assert_equal 1, File.read(@tmpf.path).lines.count
|
251
|
+
connect.close
|
252
|
+
sleep 0.5
|
253
|
+
assert_equal 2, File.read(@tmpf.path).lines.count
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
sub_test_case 'on_reload' do
|
258
|
+
def opts
|
259
|
+
{
|
260
|
+
min_processes: 5,
|
261
|
+
max_processes: 5,
|
262
|
+
on_reload: ->(_opts){ File.open(@tmpf.path, 'a'){|f| f.puts $$} },
|
263
|
+
}
|
264
|
+
end
|
265
|
+
|
266
|
+
test 'execute block when reload' do
|
267
|
+
assert_equal 0, File.read(@tmpf.path).lines.count
|
268
|
+
@prefork.reload(12345, opts)
|
269
|
+
sleep 0.5
|
270
|
+
assert_equal 5, File.read(@tmpf.path).lines.count
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
sub_test_case 'on_child_start' do
|
275
|
+
def opts
|
276
|
+
@childs = []
|
277
|
+
{
|
278
|
+
min_processes: 1,
|
279
|
+
max_processes: 2,
|
280
|
+
max_threads: 1,
|
281
|
+
standby_threads: 1,
|
282
|
+
on_child_start: ->(pid){ @childs.push pid },
|
283
|
+
}
|
284
|
+
end
|
285
|
+
|
286
|
+
test 'execute block when child start' do
|
287
|
+
assert_equal 1, @childs.count
|
288
|
+
connect.close
|
289
|
+
sleep 0.5
|
290
|
+
assert_equal 2, @childs.count
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
sub_test_case 'on_child_exit' do
|
295
|
+
def opts
|
296
|
+
@childs = []
|
297
|
+
{
|
298
|
+
min_processes: 1,
|
299
|
+
max_processes: 1,
|
300
|
+
max_idle: 0.001,
|
301
|
+
on_child_exit: ->(pid, st){ @childs.push pid; @st = st },
|
302
|
+
}
|
303
|
+
end
|
304
|
+
|
305
|
+
test 'execute block when child exit' do
|
306
|
+
assert_equal [], @childs
|
307
|
+
s = TCPSocket.new('localhost', port)
|
308
|
+
pid = s.gets.chomp.to_i
|
309
|
+
s.close
|
310
|
+
sleep 0.5
|
311
|
+
assert_equal [pid], @childs
|
312
|
+
assert_equal 0, @st.exitstatus
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
sub_test_case 'each_nonblock' do
|
317
|
+
test 'run in single thread unless timeout occur' do
|
318
|
+
@prefork.singleton_class.class_eval{public :each_nonblock}
|
319
|
+
values = Array.new(100, true)
|
320
|
+
result = []
|
321
|
+
@prefork.each_nonblock(values, 1) do |x|
|
322
|
+
result.push Thread.current
|
323
|
+
end
|
324
|
+
assert_equal result.size, values.size
|
325
|
+
assert_equal result.uniq.size, 1
|
326
|
+
end
|
327
|
+
|
328
|
+
test 'run in multiple thread if timeout occur' do
|
329
|
+
@prefork.singleton_class.class_eval{public :each_nonblock}
|
330
|
+
values = Array.new(10, true)
|
331
|
+
result = []
|
332
|
+
@prefork.each_nonblock(values, 0.1) do |x|
|
333
|
+
result.push Thread.current
|
334
|
+
sleep 0.3
|
335
|
+
end
|
336
|
+
assert_equal result.size, values.size
|
337
|
+
assert result.uniq.size == 10
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
sub_test_case 'new(port)' do
|
342
|
+
def args
|
343
|
+
[port]
|
344
|
+
end
|
345
|
+
|
346
|
+
test 'connection' do
|
347
|
+
Timeout.timeout(1){ connect }
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
sub_test_case 'new(host, port)' do
|
352
|
+
def args
|
353
|
+
['localhost', port]
|
354
|
+
end
|
355
|
+
|
356
|
+
test 'connection' do
|
357
|
+
Timeout.timeout(1){ connect }
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
sub_test_case 'new(socket)' do
|
362
|
+
def args
|
363
|
+
@sock = TCPServer.new(port)
|
364
|
+
[@sock]
|
365
|
+
end
|
366
|
+
|
367
|
+
def teardown
|
368
|
+
@sock.close
|
369
|
+
super
|
370
|
+
end
|
371
|
+
|
372
|
+
test 'connection' do
|
373
|
+
Timeout.timeout(1){ connect }
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
sub_test_case 'new(sockets)' do
|
378
|
+
def args
|
379
|
+
@socks = [TCPServer.new(port), TCPServer.new(port+1)]
|
380
|
+
[@socks]
|
381
|
+
end
|
382
|
+
|
383
|
+
def teardown
|
384
|
+
@socks.each(&:close)
|
385
|
+
super
|
386
|
+
end
|
387
|
+
|
388
|
+
test 'connection' do
|
389
|
+
Timeout.timeout(1){ connect }
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: parallel_server
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomita Masahiro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-05-
|
11
|
+
date: 2015-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Parallel TCP Server library. This is easy to make Multi-Process / Multi-Thread
|
14
14
|
server
|
@@ -20,6 +20,7 @@ extra_rdoc_files:
|
|
20
20
|
files:
|
21
21
|
- README.md
|
22
22
|
- lib/parallel_server/prefork.rb
|
23
|
+
- test/parallel_server/test_prefork.rb
|
23
24
|
homepage: http://github.com/tmtm/parallel_server
|
24
25
|
licenses:
|
25
26
|
- Ruby's
|
@@ -40,8 +41,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
40
41
|
version: '0'
|
41
42
|
requirements: []
|
42
43
|
rubyforge_project:
|
43
|
-
rubygems_version: 2.
|
44
|
+
rubygems_version: 2.4.5
|
44
45
|
signing_key:
|
45
46
|
specification_version: 4
|
46
47
|
summary: Parallel TCP Server library
|
47
|
-
test_files:
|
48
|
+
test_files:
|
49
|
+
- test/parallel_server/test_prefork.rb
|
50
|
+
has_rdoc: true
|