polyphony 0.67 → 0.71
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -1
- data/Gemfile.lock +2 -2
- data/TODO.md +0 -23
- data/bin/pdbg +91 -9
- data/ext/polyphony/backend_common.c +18 -0
- data/ext/polyphony/backend_common.h +1 -0
- data/ext/polyphony/backend_io_uring.c +2 -8
- data/ext/polyphony/backend_libev.c +2 -0
- data/lib/polyphony.rb +2 -2
- data/lib/polyphony/debugger.rb +225 -0
- data/lib/polyphony/extensions/fiber.rb +33 -43
- data/lib/polyphony/extensions/io.rb +1 -3
- data/lib/polyphony/extensions/openssl.rb +63 -1
- data/lib/polyphony/extensions/socket.rb +3 -3
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +0 -1
- data/test/stress.rb +1 -1
- data/test/test_fiber.rb +23 -7
- data/test/test_global_api.rb +0 -1
- data/test/test_process_supervision.rb +38 -9
- data/test/test_supervise.rb +183 -100
- metadata +4 -4
- data/lib/polyphony/debugger/server.rb +0 -137
@@ -27,6 +27,7 @@ module Polyphony
|
|
27
27
|
end
|
28
28
|
|
29
29
|
fiber = parent.spin(@tag, @caller, &@block)
|
30
|
+
@monitors&.each_key { |f| fiber.monitor(f) }
|
30
31
|
fiber.schedule(value) unless value.nil?
|
31
32
|
fiber
|
32
33
|
end
|
@@ -79,46 +80,34 @@ module Polyphony
|
|
79
80
|
|
80
81
|
# Fiber supervision
|
81
82
|
module FiberSupervision
|
82
|
-
def supervise(opts
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
def supervise(*fibers, **opts, &block)
|
84
|
+
block ||= supervise_opts_to_block(opts)
|
85
|
+
|
86
|
+
fibers.each do |f|
|
87
|
+
f.attach_to(self) unless f.parent == self
|
88
|
+
f.monitor(self)
|
86
89
|
end
|
90
|
+
|
91
|
+
mailbox = monitor_mailbox
|
92
|
+
|
87
93
|
while true
|
88
|
-
|
94
|
+
(fiber, result) = mailbox.shift
|
95
|
+
block&.call(fiber, result)
|
89
96
|
end
|
90
|
-
rescue Polyphony::MoveOn
|
91
|
-
# generated in #supervise_perform to stop supervisor
|
92
|
-
ensure
|
93
|
-
@on_child_done = nil
|
94
97
|
end
|
95
98
|
|
96
|
-
def
|
97
|
-
|
98
|
-
|
99
|
-
restart_fiber(fiber, opts)
|
100
|
-
elsif Fiber.current.children.empty?
|
101
|
-
Fiber.current.stop
|
102
|
-
end
|
103
|
-
rescue Polyphony::Restart
|
104
|
-
restart_all_children
|
105
|
-
rescue Exception => e
|
106
|
-
Kernel.raise e if e.source_fiber.nil? || e.source_fiber == self
|
99
|
+
def supervise_opts_to_block(opts)
|
100
|
+
block = opts[:on_done] || opts[:on_error]
|
101
|
+
return nil unless block || opts[:restart]
|
107
102
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
Fiber.current.stop
|
112
|
-
end
|
113
|
-
end
|
103
|
+
error_only = !!opts[:on_error]
|
104
|
+
restart_always = opts[:restart] == :always
|
105
|
+
restart_on_error = opts[:restart] == :on_error
|
114
106
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
fiber.restart
|
120
|
-
when :one_for_all
|
121
|
-
@children.keys.each(&:restart)
|
107
|
+
->(f, r) do
|
108
|
+
is_error = r.is_a?(Exception)
|
109
|
+
block.(f, r) if block && (!error_only || is_error)
|
110
|
+
f.restart if restart_always || (restart_on_error && is_error)
|
122
111
|
end
|
123
112
|
end
|
124
113
|
end
|
@@ -246,13 +235,6 @@ module Polyphony
|
|
246
235
|
c.terminate(graceful)
|
247
236
|
c.await
|
248
237
|
end
|
249
|
-
reap_dead_children
|
250
|
-
end
|
251
|
-
|
252
|
-
def reap_dead_children
|
253
|
-
return unless @children
|
254
|
-
|
255
|
-
@children.reject! { |f| f.dead? }
|
256
238
|
end
|
257
239
|
|
258
240
|
def detach
|
@@ -261,10 +243,17 @@ module Polyphony
|
|
261
243
|
@parent.add_child(self)
|
262
244
|
end
|
263
245
|
|
264
|
-
def
|
246
|
+
def attach_to(fiber)
|
265
247
|
@parent.remove_child(self)
|
266
|
-
@parent =
|
267
|
-
|
248
|
+
@parent = fiber
|
249
|
+
fiber.add_child(self)
|
250
|
+
end
|
251
|
+
|
252
|
+
def attach_and_monitor(fiber)
|
253
|
+
@parent.remove_child(self)
|
254
|
+
@parent = fiber
|
255
|
+
fiber.add_child(self)
|
256
|
+
monitor(fiber)
|
268
257
|
end
|
269
258
|
end
|
270
259
|
|
@@ -329,6 +318,7 @@ module Polyphony
|
|
329
318
|
inform_monitors(result, uncaught_exception)
|
330
319
|
@running = false
|
331
320
|
ensure
|
321
|
+
@parent&.remove_child(self)
|
332
322
|
# Prevent fiber from being resumed after terminating
|
333
323
|
@thread.fiber_unschedule(self)
|
334
324
|
Thread.current.switch_fiber
|
@@ -76,7 +76,7 @@ end
|
|
76
76
|
|
77
77
|
# IO instance method patches
|
78
78
|
class ::IO
|
79
|
-
def
|
79
|
+
def __parser_read_method__
|
80
80
|
:backend_read
|
81
81
|
end
|
82
82
|
|
@@ -160,8 +160,6 @@ class ::IO
|
|
160
160
|
return @read_buffer.slice!(0, idx + sep_size) if idx
|
161
161
|
|
162
162
|
result = readpartial(8192, @read_buffer, -1)
|
163
|
-
|
164
|
-
#Polyphony.backend_read(self, @read_buffer, 8192, false, -1)
|
165
163
|
return nil unless result
|
166
164
|
end
|
167
165
|
rescue EOFError
|
@@ -5,7 +5,7 @@ require_relative './socket'
|
|
5
5
|
|
6
6
|
# OpenSSL socket helper methods (to make it compatible with Socket API) and overrides
|
7
7
|
class ::OpenSSL::SSL::SSLSocket
|
8
|
-
def
|
8
|
+
def __parser_read_method__
|
9
9
|
:readpartial
|
10
10
|
end
|
11
11
|
|
@@ -114,6 +114,68 @@ end
|
|
114
114
|
|
115
115
|
# OpenSSL socket helper methods (to make it compatible with Socket API) and overrides
|
116
116
|
class ::OpenSSL::SSL::SSLServer
|
117
|
+
attr_reader :ctx
|
118
|
+
|
119
|
+
alias_method :orig_accept, :accept
|
120
|
+
def accept
|
121
|
+
# when @ctx.servername_cb is set, we use a worker thread to run the
|
122
|
+
# ssl.accept call. We need to do this because:
|
123
|
+
# - We cannot switch fibers inside of the servername_cb proc (see
|
124
|
+
# https://github.com/ruby/openssl/issues/415)
|
125
|
+
# - We don't want to stop the world while we're busy provisioning an ACME
|
126
|
+
# certificate
|
127
|
+
if @use_accept_worker.nil?
|
128
|
+
if (@use_accept_worker = use_accept_worker_thread?)
|
129
|
+
start_accept_worker_thread
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
sock, = @svr.accept
|
134
|
+
begin
|
135
|
+
ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
|
136
|
+
ssl.sync_close = true
|
137
|
+
if @use_accept_worker
|
138
|
+
@accept_worker_fiber << [ssl, Fiber.current]
|
139
|
+
receive
|
140
|
+
else
|
141
|
+
ssl.accept
|
142
|
+
end
|
143
|
+
ssl
|
144
|
+
rescue Exception => ex
|
145
|
+
if ssl
|
146
|
+
ssl.close
|
147
|
+
else
|
148
|
+
sock.close
|
149
|
+
end
|
150
|
+
raise ex
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def start_accept_worker_thread
|
155
|
+
fiber = Fiber.current
|
156
|
+
@accept_worker_thread = Thread.new do
|
157
|
+
fiber << Fiber.current
|
158
|
+
loop do
|
159
|
+
socket, peer = receive
|
160
|
+
socket.accept
|
161
|
+
peer << socket
|
162
|
+
rescue => e
|
163
|
+
peer.schedule(e) if fiber
|
164
|
+
end
|
165
|
+
end
|
166
|
+
@accept_worker_fiber = receive
|
167
|
+
end
|
168
|
+
|
169
|
+
def use_accept_worker_thread?
|
170
|
+
!!@ctx.servername_cb
|
171
|
+
end
|
172
|
+
|
173
|
+
alias_method :orig_close, :close
|
174
|
+
def close
|
175
|
+
@accept_worker_thread&.kill
|
176
|
+
orig_close
|
177
|
+
end
|
178
|
+
|
117
179
|
def accept_loop(ignore_errors = true)
|
118
180
|
loop do
|
119
181
|
yield accept
|
@@ -6,7 +6,7 @@ require_relative './io'
|
|
6
6
|
require_relative '../core/thread_pool'
|
7
7
|
|
8
8
|
class BasicSocket
|
9
|
-
def
|
9
|
+
def __parser_read_method__
|
10
10
|
:backend_recv
|
11
11
|
end
|
12
12
|
end
|
@@ -206,7 +206,7 @@ class ::TCPSocket
|
|
206
206
|
# Polyphony.backend_send(self, mesg, 0)
|
207
207
|
# end
|
208
208
|
|
209
|
-
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof)
|
209
|
+
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
|
210
210
|
result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
|
211
211
|
raise EOFError if !result && raise_on_eof
|
212
212
|
result
|
@@ -299,7 +299,7 @@ class ::UNIXSocket
|
|
299
299
|
Polyphony.backend_send(self, mesg, 0)
|
300
300
|
end
|
301
301
|
|
302
|
-
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof)
|
302
|
+
def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
|
303
303
|
result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
|
304
304
|
raise EOFError if !result && raise_on_eof
|
305
305
|
result
|
data/lib/polyphony/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -47,7 +47,6 @@ class MiniTest::Test
|
|
47
47
|
def setup
|
48
48
|
# trace "* setup #{self.name}"
|
49
49
|
Fiber.current.setup_main_fiber
|
50
|
-
Fiber.current.instance_variable_set(:@auto_watcher, nil)
|
51
50
|
Thread.current.backend.finalize
|
52
51
|
Thread.current.backend = Polyphony::Backend.new
|
53
52
|
sleep 0.001
|
data/test/stress.rb
CHANGED
data/test/test_fiber.rb
CHANGED
@@ -67,8 +67,6 @@ class FiberTest < MiniTest::Test
|
|
67
67
|
}
|
68
68
|
Fiber.await(f2, f3)
|
69
69
|
assert_equal [:foo, :bar, :baz], buffer
|
70
|
-
assert_equal [f1], Fiber.current.children
|
71
|
-
Fiber.current.reap_dead_children
|
72
70
|
assert_equal [], Fiber.current.children
|
73
71
|
end
|
74
72
|
|
@@ -93,8 +91,6 @@ class FiberTest < MiniTest::Test
|
|
93
91
|
f1.stop
|
94
92
|
|
95
93
|
snooze
|
96
|
-
assert_equal [f1, f2, f3], Fiber.current.children
|
97
|
-
Fiber.current.reap_dead_children
|
98
94
|
assert_equal [], Fiber.current.children
|
99
95
|
end
|
100
96
|
|
@@ -602,7 +598,6 @@ class FiberTest < MiniTest::Test
|
|
602
598
|
|
603
599
|
f.stop
|
604
600
|
snooze
|
605
|
-
Fiber.current.reap_dead_children
|
606
601
|
assert_equal [], Fiber.current.children
|
607
602
|
end
|
608
603
|
|
@@ -791,7 +786,7 @@ class FiberTest < MiniTest::Test
|
|
791
786
|
], buf
|
792
787
|
end
|
793
788
|
|
794
|
-
def
|
789
|
+
def test_attach_to
|
795
790
|
buf = []
|
796
791
|
child = nil
|
797
792
|
parent = spin(:parent) do
|
@@ -809,7 +804,7 @@ class FiberTest < MiniTest::Test
|
|
809
804
|
|
810
805
|
snooze
|
811
806
|
assert_equal parent, child.parent
|
812
|
-
child.
|
807
|
+
child.attach_to(new_parent)
|
813
808
|
assert_equal new_parent, child.parent
|
814
809
|
parent.await
|
815
810
|
|
@@ -954,6 +949,27 @@ class MailboxTest < MiniTest::Test
|
|
954
949
|
assert_equal ['foo'] * 100, messages
|
955
950
|
end
|
956
951
|
|
952
|
+
def test_receive_exception
|
953
|
+
e = RuntimeError.new 'foo'
|
954
|
+
spin { Fiber.current.parent << e }
|
955
|
+
r = receive
|
956
|
+
assert_equal e, r
|
957
|
+
|
958
|
+
spin { Fiber.current.parent.schedule e }
|
959
|
+
assert_raises(RuntimeError) { receive }
|
960
|
+
end
|
961
|
+
|
962
|
+
def test_receive_cross_thread_exception
|
963
|
+
e = RuntimeError.new 'foo'
|
964
|
+
f = Fiber.current
|
965
|
+
Thread.new { f << e }
|
966
|
+
r = receive
|
967
|
+
assert_equal e, r
|
968
|
+
|
969
|
+
Thread.new { f.schedule e }
|
970
|
+
assert_raises(RuntimeError) { receive }
|
971
|
+
end
|
972
|
+
|
957
973
|
def test_receive_all_pending
|
958
974
|
assert_equal [], receive_all_pending
|
959
975
|
|
data/test/test_global_api.rb
CHANGED
@@ -6,7 +6,7 @@ class ProcessSupervisionTest < MiniTest::Test
|
|
6
6
|
def test_process_supervisor_with_block
|
7
7
|
i, o = IO.pipe
|
8
8
|
|
9
|
-
|
9
|
+
watcher = spin do
|
10
10
|
Polyphony.watch_process do
|
11
11
|
i.close
|
12
12
|
sleep 5
|
@@ -14,31 +14,60 @@ class ProcessSupervisionTest < MiniTest::Test
|
|
14
14
|
o << 'foo'
|
15
15
|
o.close
|
16
16
|
end
|
17
|
-
supervise(on_error: :restart)
|
18
17
|
end
|
19
18
|
|
19
|
+
supervisor = spin { supervise(watcher, restart: :always) }
|
20
|
+
|
20
21
|
sleep 0.05
|
21
|
-
|
22
|
-
|
22
|
+
supervisor.terminate
|
23
|
+
supervisor.await
|
23
24
|
|
24
25
|
o.close
|
25
26
|
msg = i.read
|
26
|
-
i.close
|
27
27
|
assert_equal 'foo', msg
|
28
28
|
end
|
29
29
|
|
30
|
+
def test_process_supervisor_restart_with_block
|
31
|
+
i1, o1 = IO.pipe
|
32
|
+
i2, o2 = IO.pipe
|
33
|
+
|
34
|
+
count = 0
|
35
|
+
watcher = spin do
|
36
|
+
count += 1
|
37
|
+
Polyphony.watch_process do
|
38
|
+
i1.gets
|
39
|
+
o2.puts count
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
supervisor = spin { supervise(watcher, restart: :always) }
|
44
|
+
|
45
|
+
o1.puts
|
46
|
+
l = i2.gets
|
47
|
+
assert_equal "1\n", l
|
48
|
+
|
49
|
+
o1.puts
|
50
|
+
l = i2.gets
|
51
|
+
assert_equal "2\n", l
|
52
|
+
|
53
|
+
o1.puts
|
54
|
+
l = i2.gets
|
55
|
+
assert_equal "3\n", l
|
56
|
+
end
|
57
|
+
|
30
58
|
def test_process_supervisor_with_cmd
|
31
59
|
fn = '/tmp/test_process_supervisor_with_cmd'
|
32
60
|
FileUtils.rm(fn) rescue nil
|
33
61
|
|
34
|
-
|
62
|
+
watcher = spin do
|
35
63
|
Polyphony.watch_process("echo foo >> #{fn}")
|
36
|
-
supervise(on_error: :restart)
|
37
64
|
end
|
38
65
|
|
66
|
+
supervisor = spin { supervise(watcher) }
|
67
|
+
|
39
68
|
sleep 0.05
|
40
|
-
|
41
|
-
|
69
|
+
supervisor.terminate
|
70
|
+
supervisor.await
|
42
71
|
|
43
72
|
assert_equal "foo\n", IO.read(fn)
|
44
73
|
|
data/test/test_supervise.rb
CHANGED
@@ -2,103 +2,186 @@
|
|
2
2
|
|
3
3
|
require_relative 'helper'
|
4
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
|
-
|
5
|
+
class SuperviseTest < MiniTest::Test
|
6
|
+
def test_supervise_with_block
|
7
|
+
buffer = []
|
8
|
+
f1 = spin(:f1) { receive }
|
9
|
+
f2 = spin(:f2) { receive }
|
10
|
+
supervisor = spin(:supervisor) { supervise(f1, f2) { |*args| buffer << args } }
|
11
|
+
|
12
|
+
snooze
|
13
|
+
f1 << 'foo'
|
14
|
+
f1.await
|
15
|
+
10.times { snooze }
|
16
|
+
assert_equal [[f1, 'foo']], buffer
|
17
|
+
|
18
|
+
f2 << 'bar'
|
19
|
+
f2.await
|
20
|
+
assert_equal [[f1, 'foo'], [f2, 'bar']], buffer
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_supervise_with_on_done
|
24
|
+
buffer = []
|
25
|
+
f1 = spin(:f1) { receive }
|
26
|
+
f2 = spin(:f2) { receive }
|
27
|
+
supervisor = spin(:supervisor) do
|
28
|
+
supervise(f1, f2, on_done: ->(*args) { buffer << args })
|
29
|
+
end
|
30
|
+
|
31
|
+
snooze
|
32
|
+
f1 << 'foo'
|
33
|
+
f1.await
|
34
|
+
10.times { snooze }
|
35
|
+
assert_equal [[f1, 'foo']], buffer
|
36
|
+
|
37
|
+
f2 << 'bar'
|
38
|
+
f2.await
|
39
|
+
assert_equal [[f1, 'foo'], [f2, 'bar']], buffer
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_supervise_with_on_error
|
43
|
+
buffer = []
|
44
|
+
f1 = spin(:f1) { receive }
|
45
|
+
f2 = spin(:f2) { receive }
|
46
|
+
supervisor = spin(:supervisor) do
|
47
|
+
supervise(f1, f2, on_error: ->(*args) { buffer << args })
|
48
|
+
end
|
49
|
+
|
50
|
+
snooze
|
51
|
+
f1 << 'foo'
|
52
|
+
f1.await
|
53
|
+
10.times { snooze }
|
54
|
+
assert_equal [], buffer
|
55
|
+
|
56
|
+
e = RuntimeError.new('blah')
|
57
|
+
f2.raise(e)
|
58
|
+
3.times { snooze }
|
59
|
+
assert_equal [[f2, e]], buffer
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_supervise_with_manual_restart
|
63
|
+
buffer = []
|
64
|
+
f1 = spin(:f1) { receive }
|
65
|
+
supervisor = spin(:supervisor) do
|
66
|
+
supervise(f1) do |f, r|
|
67
|
+
buffer << [f, r]
|
68
|
+
f.restart
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
snooze
|
73
|
+
f1 << 'foo'
|
74
|
+
f1.await
|
75
|
+
snooze
|
76
|
+
assert_equal [[f1, 'foo']], buffer
|
77
|
+
|
78
|
+
10.times { snooze }
|
79
|
+
|
80
|
+
assert_equal 1, supervisor.children.size
|
81
|
+
f2 = supervisor.children.first
|
82
|
+
assert f1 != f2
|
83
|
+
assert_equal :f1, f2.tag
|
84
|
+
assert_equal supervisor, f2.parent
|
85
|
+
|
86
|
+
e = RuntimeError.new('bar')
|
87
|
+
f2.raise(e)
|
88
|
+
f2.await rescue nil
|
89
|
+
3.times { snooze }
|
90
|
+
assert_equal [[f1, 'foo'], [f2, e]], buffer
|
91
|
+
|
92
|
+
assert_equal 1, supervisor.children.size
|
93
|
+
f3 = supervisor.children.first
|
94
|
+
assert f2 != f3
|
95
|
+
assert f1 != f3
|
96
|
+
assert_equal :f1, f3.tag
|
97
|
+
assert_equal supervisor, f3.parent
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_supervise_with_restart_always
|
101
|
+
buffer = []
|
102
|
+
f1 = spin(:f1) do
|
103
|
+
buffer << receive
|
104
|
+
rescue => e
|
105
|
+
buffer << e
|
106
|
+
e
|
107
|
+
end
|
108
|
+
supervisor = spin(:supervisor) { supervise(f1, restart: :always) }
|
109
|
+
|
110
|
+
snooze
|
111
|
+
f1 << 'foo'
|
112
|
+
f1.await
|
113
|
+
snooze
|
114
|
+
assert_equal ['foo'], buffer
|
115
|
+
|
116
|
+
10.times { snooze }
|
117
|
+
|
118
|
+
assert_equal 1, supervisor.children.size
|
119
|
+
f2 = supervisor.children.first
|
120
|
+
assert f1 != f2
|
121
|
+
assert_equal :f1, f2.tag
|
122
|
+
assert_equal supervisor, f2.parent
|
123
|
+
|
124
|
+
e = RuntimeError.new('bar')
|
125
|
+
f2.raise(e)
|
126
|
+
f2.await rescue nil
|
127
|
+
3.times { snooze }
|
128
|
+
assert_equal ['foo', e], buffer
|
129
|
+
|
130
|
+
assert_equal 1, supervisor.children.size
|
131
|
+
f3 = supervisor.children.first
|
132
|
+
assert f2 != f3
|
133
|
+
assert f1 != f3
|
134
|
+
assert_equal :f1, f3.tag
|
135
|
+
assert_equal supervisor, f3.parent
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_supervise_with_restart_on_error
|
139
|
+
buffer = []
|
140
|
+
f1 = spin(:f1) do
|
141
|
+
buffer << receive
|
142
|
+
rescue => e
|
143
|
+
buffer << e
|
144
|
+
e
|
145
|
+
end
|
146
|
+
supervisor = spin(:supervisor) { supervise(f1, restart: :on_error) }
|
147
|
+
|
148
|
+
snooze
|
149
|
+
e = RuntimeError.new('bar')
|
150
|
+
f1.raise(e)
|
151
|
+
f1.await rescue nil
|
152
|
+
snooze
|
153
|
+
assert_equal [e], buffer
|
154
|
+
|
155
|
+
10.times { snooze }
|
156
|
+
|
157
|
+
assert_equal 1, supervisor.children.size
|
158
|
+
f2 = supervisor.children.first
|
159
|
+
assert f1 != f2
|
160
|
+
assert_equal :f1, f2.tag
|
161
|
+
assert_equal supervisor, f2.parent
|
162
|
+
|
163
|
+
f2 << 'foo'
|
164
|
+
f2.await rescue nil
|
165
|
+
3.times { snooze }
|
166
|
+
assert_equal [e, 'foo'], buffer
|
167
|
+
|
168
|
+
assert_equal 0, supervisor.children.size
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_supervise_terminate
|
172
|
+
buffer = []
|
173
|
+
f1 = spin(:f1) do
|
174
|
+
buffer << receive
|
175
|
+
rescue => e
|
176
|
+
buffer << e
|
177
|
+
e
|
178
|
+
end
|
179
|
+
supervisor = spin(:supervisor) { supervise(f1, restart: :on_error) }
|
180
|
+
|
181
|
+
sleep 0.05
|
182
|
+
supervisor.terminate
|
183
|
+
supervisor.await
|
184
|
+
|
185
|
+
assert_equal [], buffer
|
186
|
+
end
|
187
|
+
end
|