polyphony 0.32 → 0.33
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +20 -0
- data/.rubocop.yml +14 -1
- data/CHANGELOG.md +10 -2
- data/Gemfile.lock +1 -1
- data/README.md +4 -0
- data/TODO.md +116 -1
- data/docs/_sass/custom/custom.scss +4 -0
- data/docs/_sass/overrides.scss +4 -6
- data/docs/getting-started/installing.md +2 -2
- data/docs/getting-started/tutorial.md +17 -15
- data/docs/index.md +18 -23
- data/docs/main-concepts/concurrency.md +1 -1
- data/ext/gyro/async.c +27 -0
- data/ext/gyro/gyro.h +1 -0
- data/ext/gyro/queue.c +10 -9
- data/ext/gyro/selector.c +3 -5
- data/ext/gyro/thread.c +6 -17
- data/lib/polyphony.rb +1 -0
- data/lib/polyphony/core/exceptions.rb +4 -1
- data/lib/polyphony/core/global_api.rb +4 -0
- data/lib/polyphony/extensions/core.rb +4 -3
- data/lib/polyphony/extensions/fiber.rb +72 -11
- data/lib/polyphony/extensions/thread.rb +20 -7
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +2 -2
- data/test/stress.rb +20 -0
- data/test/test_fiber.rb +158 -4
- data/test/test_global_api.rb +21 -14
- data/test/test_kernel.rb +23 -0
- data/test/test_signal.rb +1 -1
- data/test/test_thread.rb +4 -3
- data/test/test_thread_pool.rb +2 -2
- metadata +6 -4
data/test/test_fiber.rb
CHANGED
@@ -168,6 +168,7 @@ class FiberTest < MiniTest::Test
|
|
168
168
|
end
|
169
169
|
assert_kind_of Hash, result
|
170
170
|
assert_kind_of RuntimeError, result[:error]
|
171
|
+
assert_equal f, result[:error].source_fiber
|
171
172
|
ensure
|
172
173
|
f&.stop
|
173
174
|
end
|
@@ -180,7 +181,7 @@ class FiberTest < MiniTest::Test
|
|
180
181
|
2.times { snooze }
|
181
182
|
result << 2
|
182
183
|
end
|
183
|
-
spin { f.raise }
|
184
|
+
f2 = spin { f.raise }
|
184
185
|
assert_equal 0, result.size
|
185
186
|
begin
|
186
187
|
f.await
|
@@ -190,6 +191,7 @@ class FiberTest < MiniTest::Test
|
|
190
191
|
assert_equal 1, result.size
|
191
192
|
assert_equal 1, result[0]
|
192
193
|
assert_kind_of RuntimeError, error
|
194
|
+
assert_equal f, error.source_fiber
|
193
195
|
ensure
|
194
196
|
f&.stop
|
195
197
|
end
|
@@ -250,7 +252,7 @@ class FiberTest < MiniTest::Test
|
|
250
252
|
2.times { snooze }
|
251
253
|
result << 2
|
252
254
|
end
|
253
|
-
spin { f.raise 'foo' }
|
255
|
+
f2 = spin { f.raise 'foo' }
|
254
256
|
assert_equal 0, result.size
|
255
257
|
begin
|
256
258
|
f.await
|
@@ -261,6 +263,7 @@ class FiberTest < MiniTest::Test
|
|
261
263
|
assert_equal 1, result[0]
|
262
264
|
assert_kind_of RuntimeError, error
|
263
265
|
assert_equal 'foo', error.message
|
266
|
+
assert_equal f, error.source_fiber
|
264
267
|
ensure
|
265
268
|
f&.stop
|
266
269
|
end
|
@@ -663,7 +666,6 @@ class FiberTest < MiniTest::Test
|
|
663
666
|
o.close
|
664
667
|
end
|
665
668
|
snooze
|
666
|
-
ensure
|
667
669
|
end
|
668
670
|
o.close
|
669
671
|
Gyro::Child.new(pid).await
|
@@ -827,6 +829,7 @@ class FiberControlTest < MiniTest::Test
|
|
827
829
|
end
|
828
830
|
assert_kind_of RuntimeError, error
|
829
831
|
assert_equal 'foo', error.message
|
832
|
+
assert_equal f1, error.source_fiber
|
830
833
|
|
831
834
|
assert_equal :dead, f1.state
|
832
835
|
assert_equal :dead, f2.state
|
@@ -863,6 +866,7 @@ class FiberControlTest < MiniTest::Test
|
|
863
866
|
|
864
867
|
assert_kind_of RuntimeError, result
|
865
868
|
assert_equal 'foo', result.message
|
869
|
+
assert_equal f1, result.source_fiber
|
866
870
|
assert_equal :dead, f1.state
|
867
871
|
assert_equal :dead, f2.state
|
868
872
|
end
|
@@ -874,4 +878,154 @@ class FiberControlTest < MiniTest::Test
|
|
874
878
|
result = Fiber.select(f1, f2)
|
875
879
|
assert_equal [f2, :baz], result
|
876
880
|
end
|
877
|
-
end
|
881
|
+
end
|
882
|
+
|
883
|
+
class SupervisionTest < MiniTest::Test
|
884
|
+
def test_exception_during_termination
|
885
|
+
f2 = nil
|
886
|
+
f = spin do
|
887
|
+
f2 = spin do
|
888
|
+
sleep
|
889
|
+
rescue Polyphony::Terminate
|
890
|
+
raise 'foo'
|
891
|
+
end
|
892
|
+
sleep
|
893
|
+
end
|
894
|
+
|
895
|
+
sleep 0.01
|
896
|
+
e = nil
|
897
|
+
begin
|
898
|
+
f.terminate
|
899
|
+
f.await
|
900
|
+
rescue => e
|
901
|
+
end
|
902
|
+
|
903
|
+
assert_kind_of RuntimeError, e
|
904
|
+
assert_equal 'foo', e.message
|
905
|
+
assert_equal f2, e.source_fiber
|
906
|
+
end
|
907
|
+
end
|
908
|
+
|
909
|
+
class RestartTest < MiniTest::Test
|
910
|
+
def test_restart
|
911
|
+
buffer = []
|
912
|
+
f = spin {
|
913
|
+
buffer << 1
|
914
|
+
receive
|
915
|
+
buffer << 2
|
916
|
+
}
|
917
|
+
snooze
|
918
|
+
assert_equal [1], buffer
|
919
|
+
f2 = f.restart
|
920
|
+
assert_equal f2, f
|
921
|
+
assert_equal [1], buffer
|
922
|
+
snooze
|
923
|
+
assert_equal [1, 1], buffer
|
924
|
+
|
925
|
+
f << 'foo'
|
926
|
+
sleep 0.1
|
927
|
+
assert_equal [1, 1, 2], buffer
|
928
|
+
end
|
929
|
+
|
930
|
+
def test_restart_after_finalization
|
931
|
+
buffer = []
|
932
|
+
parent = spin {
|
933
|
+
sleep
|
934
|
+
}
|
935
|
+
|
936
|
+
f = parent.spin { |v|
|
937
|
+
buffer << Fiber.current
|
938
|
+
buffer << v
|
939
|
+
buffer << receive
|
940
|
+
buffer << :done
|
941
|
+
}
|
942
|
+
f.schedule('foo')
|
943
|
+
f << 'bar'
|
944
|
+
snooze
|
945
|
+
f.await
|
946
|
+
|
947
|
+
assert_equal [f, 'foo', 'bar', :done], buffer
|
948
|
+
assert_equal parent, f.parent
|
949
|
+
|
950
|
+
f2 = f.restart('baz')
|
951
|
+
assert f2 != f
|
952
|
+
assert_equal parent, f2.parent
|
953
|
+
|
954
|
+
f2 << 42
|
955
|
+
f2.await
|
956
|
+
assert_equal [f, 'foo', 'bar', :done, f2, 'baz', 42, :done], buffer
|
957
|
+
end
|
958
|
+
end
|
959
|
+
|
960
|
+
class SuperviseTest < MiniTest::Test
|
961
|
+
def test_supervise
|
962
|
+
p = spin { supervise }
|
963
|
+
snooze
|
964
|
+
f1 = p.spin { receive }
|
965
|
+
f2 = p.spin { receive }
|
966
|
+
|
967
|
+
snooze
|
968
|
+
assert_equal p.state, :waiting
|
969
|
+
f1 << 'foo'
|
970
|
+
f1.await
|
971
|
+
snooze
|
972
|
+
|
973
|
+
assert_equal :waiting, p.state
|
974
|
+
assert_equal :waiting, f2.state
|
975
|
+
|
976
|
+
f2 << 'bar'
|
977
|
+
f2.await
|
978
|
+
snooze
|
979
|
+
|
980
|
+
assert_equal :waiting, p.state
|
981
|
+
end
|
982
|
+
|
983
|
+
def test_supervise_with_restart
|
984
|
+
parent = spin { supervise(on_error: :restart) }
|
985
|
+
snooze
|
986
|
+
|
987
|
+
buffer = []
|
988
|
+
f1 = parent.spin do
|
989
|
+
buffer << 'f1'
|
990
|
+
buffer << receive
|
991
|
+
end
|
992
|
+
|
993
|
+
snooze
|
994
|
+
assert_equal ['f1'], buffer
|
995
|
+
|
996
|
+
f1.raise 'foo'
|
997
|
+
|
998
|
+
3.times { snooze }
|
999
|
+
|
1000
|
+
assert_equal ['f1', 'f1'], buffer
|
1001
|
+
assert_equal :dead, f1.state
|
1002
|
+
|
1003
|
+
# f1 should have been restarted by supervisor
|
1004
|
+
f1 = parent.children.first
|
1005
|
+
assert_kind_of Fiber, f1
|
1006
|
+
f1 << 'foo'
|
1007
|
+
|
1008
|
+
f1.await
|
1009
|
+
3.times { snooze }
|
1010
|
+
|
1011
|
+
assert_equal ['f1', 'f1', 'foo'], buffer
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
def test_supervise_with_block
|
1015
|
+
failed = []
|
1016
|
+
p = spin do
|
1017
|
+
supervise(on_error: :restart) { |f, e| failed << [f, e] }
|
1018
|
+
end
|
1019
|
+
snooze
|
1020
|
+
f1 = p.spin { receive }
|
1021
|
+
snooze
|
1022
|
+
|
1023
|
+
f1.raise 'foo'
|
1024
|
+
3.times { snooze }
|
1025
|
+
|
1026
|
+
assert_equal 1, failed.size
|
1027
|
+
assert_equal f1, failed.first[0]
|
1028
|
+
assert_kind_of RuntimeError, failed.first[1]
|
1029
|
+
assert_equal 'foo', failed.first[1].message
|
1030
|
+
end
|
1031
|
+
end
|
data/test/test_global_api.rb
CHANGED
@@ -40,6 +40,18 @@ class SpinTest < MiniTest::Test
|
|
40
40
|
suspend
|
41
41
|
assert_nil fiber.result
|
42
42
|
end
|
43
|
+
|
44
|
+
def test_spin_without_tag
|
45
|
+
f = spin { }
|
46
|
+
assert_kind_of Fiber, f
|
47
|
+
assert_nil f.tag
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_spin_with_tag
|
51
|
+
f = spin(:foo) { }
|
52
|
+
assert_kind_of Fiber, f
|
53
|
+
assert_equal :foo, f.tag
|
54
|
+
end
|
43
55
|
end
|
44
56
|
|
45
57
|
class ExceptionTest < MiniTest::Test
|
@@ -111,20 +123,6 @@ class MoveOnAfterTest < MiniTest::Test
|
|
111
123
|
end
|
112
124
|
end
|
113
125
|
|
114
|
-
class SpinTest < MiniTest::Test
|
115
|
-
def test_spin_without_tag
|
116
|
-
f = spin { }
|
117
|
-
assert_kind_of Fiber, f
|
118
|
-
assert_nil f.tag
|
119
|
-
end
|
120
|
-
|
121
|
-
def test_spin_with_tag
|
122
|
-
f = spin(:foo) { }
|
123
|
-
assert_kind_of Fiber, f
|
124
|
-
assert_equal :foo, f.tag
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
126
|
class SpinLoopTest < MiniTest::Test
|
129
127
|
def test_spin_loop
|
130
128
|
buffer = []
|
@@ -195,6 +193,15 @@ class ThrottledLoopTest < MiniTest::Test
|
|
195
193
|
end
|
196
194
|
|
197
195
|
class GlobalAPIEtcTest < MiniTest::Test
|
196
|
+
def test_after
|
197
|
+
buffer = []
|
198
|
+
f = after(0.001) { buffer << 2 }
|
199
|
+
snooze
|
200
|
+
assert_equal [], buffer
|
201
|
+
sleep 0.001
|
202
|
+
assert_equal [2], buffer
|
203
|
+
end
|
204
|
+
|
198
205
|
def test_every
|
199
206
|
buffer = []
|
200
207
|
f = spin do
|
data/test/test_kernel.rb
CHANGED
@@ -21,6 +21,29 @@ class KernelTest < MiniTest::Test
|
|
21
21
|
timer&.stop
|
22
22
|
end
|
23
23
|
|
24
|
+
def patch_open3
|
25
|
+
class << Open3
|
26
|
+
alias_method :orig_popen2, :popen2
|
27
|
+
def popen2(*args)
|
28
|
+
raise SystemCallError, 'foo'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def unpatch_open3
|
34
|
+
class << Open3
|
35
|
+
alias_method :popen2, :orig_popen2
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_system_method_with_system_call_error
|
40
|
+
patch_open3
|
41
|
+
result = system('foo')
|
42
|
+
assert_nil result
|
43
|
+
ensure
|
44
|
+
unpatch_open3
|
45
|
+
end
|
46
|
+
|
24
47
|
def test_backtick_method
|
25
48
|
counter = 0
|
26
49
|
timer = spin { throttled_loop(200) { counter += 1 } }
|
data/test/test_signal.rb
CHANGED
data/test/test_thread.rb
CHANGED
@@ -50,7 +50,6 @@ class ThreadTest < MiniTest::Test
|
|
50
50
|
buffer = []
|
51
51
|
spin { (1..3).each { |i| snooze; buffer << i } }
|
52
52
|
t = Thread.new { sleep 0.01; buffer << 4; :foo }
|
53
|
-
|
54
53
|
r = t.await
|
55
54
|
|
56
55
|
assert_equal [1, 2, 3, 4], buffer
|
@@ -92,16 +91,18 @@ class ThreadTest < MiniTest::Test
|
|
92
91
|
lineno = __LINE__ + 1
|
93
92
|
t = Thread.new { sleep 1 }
|
94
93
|
str = format(
|
95
|
-
"#<Thread:%d %s:%d
|
94
|
+
"#<Thread:%d %s:%d",
|
96
95
|
t.object_id,
|
97
96
|
__FILE__,
|
98
97
|
lineno,
|
99
98
|
)
|
100
|
-
|
99
|
+
assert t.inspect =~ /#{str}/
|
101
100
|
rescue => e
|
102
101
|
p e
|
102
|
+
puts e.backtrace.join("\n")
|
103
103
|
ensure
|
104
104
|
t.kill
|
105
|
+
sleep 0.005
|
105
106
|
t.join
|
106
107
|
end
|
107
108
|
|
data/test/test_thread_pool.rb
CHANGED
@@ -65,10 +65,10 @@ class ThreadPoolTest < MiniTest::Test
|
|
65
65
|
end
|
66
66
|
elapsed = Time.now - t0
|
67
67
|
|
68
|
-
assert elapsed < 0.
|
68
|
+
assert elapsed < 0.007
|
69
69
|
assert buffer.size < 2
|
70
70
|
|
71
|
-
sleep 0.
|
71
|
+
sleep 0.08 # allow time for threads to spawn
|
72
72
|
assert_equal @pool.size, threads.uniq.size
|
73
73
|
assert_equal (0..9).to_a, buffer.sort
|
74
74
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: polyphony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.33'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: modulation
|
@@ -243,6 +243,7 @@ extra_rdoc_files:
|
|
243
243
|
- README.md
|
244
244
|
files:
|
245
245
|
- ".gitbook.yaml"
|
246
|
+
- ".github/workflows/test.yml"
|
246
247
|
- ".gitignore"
|
247
248
|
- ".rubocop.yml"
|
248
249
|
- ".vscode/launch.json"
|
@@ -402,6 +403,7 @@ files:
|
|
402
403
|
- test/eg.rb
|
403
404
|
- test/helper.rb
|
404
405
|
- test/run.rb
|
406
|
+
- test/stress.rb
|
405
407
|
- test/test_async.rb
|
406
408
|
- test/test_ext.rb
|
407
409
|
- test/test_fiber.rb
|
@@ -415,7 +417,7 @@ files:
|
|
415
417
|
- test/test_throttler.rb
|
416
418
|
- test/test_timer.rb
|
417
419
|
- test/test_trace.rb
|
418
|
-
homepage: https://
|
420
|
+
homepage: https://digital-fabric.github.io/polyphony
|
419
421
|
licenses:
|
420
422
|
- MIT
|
421
423
|
metadata:
|
@@ -445,5 +447,5 @@ requirements: []
|
|
445
447
|
rubygems_version: 3.0.6
|
446
448
|
signing_key:
|
447
449
|
specification_version: 4
|
448
|
-
summary:
|
450
|
+
summary: Fine grained concurrency for Ruby
|
449
451
|
test_files: []
|