polyphony 0.67 → 0.71
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/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
|