polyphony 0.33 → 0.34

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/Gemfile.lock +1 -1
  4. data/TODO.md +93 -68
  5. data/bin/polyphony-debug +87 -0
  6. data/docs/_includes/nav.html +5 -1
  7. data/docs/_sass/overrides.scss +4 -1
  8. data/docs/api-reference.md +11 -0
  9. data/docs/api-reference/exception.md +27 -0
  10. data/docs/api-reference/fiber.md +407 -0
  11. data/docs/api-reference/io.md +36 -0
  12. data/docs/api-reference/object.md +99 -0
  13. data/docs/api-reference/polyphony-baseexception.md +33 -0
  14. data/docs/api-reference/polyphony-cancel.md +26 -0
  15. data/docs/api-reference/polyphony-moveon.md +24 -0
  16. data/docs/api-reference/polyphony-net.md +20 -0
  17. data/docs/api-reference/polyphony-process.md +28 -0
  18. data/docs/api-reference/polyphony-resourcepool.md +59 -0
  19. data/docs/api-reference/polyphony-restart.md +18 -0
  20. data/docs/api-reference/polyphony-terminate.md +18 -0
  21. data/docs/api-reference/polyphony-threadpool.md +67 -0
  22. data/docs/api-reference/polyphony-throttler.md +77 -0
  23. data/docs/api-reference/polyphony.md +36 -0
  24. data/docs/api-reference/thread.md +88 -0
  25. data/docs/getting-started/tutorial.md +59 -156
  26. data/docs/index.md +2 -0
  27. data/examples/core/forever_sleep.rb +19 -0
  28. data/examples/core/xx-caller.rb +12 -0
  29. data/examples/core/xx-exception-backtrace.rb +40 -0
  30. data/examples/core/xx-fork-spin.rb +42 -0
  31. data/examples/core/xx-spin-fork.rb +49 -0
  32. data/examples/core/xx-supervise-process.rb +30 -0
  33. data/ext/gyro/gyro.h +1 -0
  34. data/ext/gyro/selector.c +8 -0
  35. data/ext/gyro/thread.c +8 -2
  36. data/lib/polyphony.rb +64 -17
  37. data/lib/polyphony/adapters/process.rb +29 -0
  38. data/lib/polyphony/adapters/trace.rb +6 -4
  39. data/lib/polyphony/core/exceptions.rb +5 -0
  40. data/lib/polyphony/core/global_api.rb +15 -0
  41. data/lib/polyphony/extensions/fiber.rb +89 -59
  42. data/lib/polyphony/version.rb +1 -1
  43. data/test/test_fiber.rb +23 -75
  44. data/test/test_global_api.rb +39 -0
  45. data/test/test_kernel.rb +5 -7
  46. data/test/test_process_supervision.rb +46 -0
  47. data/test/test_signal.rb +2 -3
  48. data/test/test_supervise.rb +103 -0
  49. metadata +29 -2
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.33'
4
+ VERSION = '0.34'
5
5
  end
@@ -659,20 +659,41 @@ class FiberTest < MiniTest::Test
659
659
  i, o = IO.pipe
660
660
  pid = Polyphony.fork do
661
661
  i.close
662
- f = spin do
662
+ spin do
663
663
  sleep 100
664
664
  rescue Exception => e
665
665
  o << e.class.to_s
666
666
  o.close
667
+ raise e
667
668
  end
668
- snooze
669
+ suspend
669
670
  end
670
671
  o.close
672
+ spin do
673
+ sleep 0.2
674
+ Process.kill('TERM', pid)
675
+ end
671
676
  Gyro::Child.new(pid).await
672
677
  klass = i.read
673
678
  i.close
674
679
  assert_equal 'Polyphony::Terminate', klass
675
680
  end
681
+
682
+ def test_setup_raw
683
+ buffer = []
684
+ f = Fiber.new { buffer << receive }
685
+
686
+ assert_raises(NoMethodError) { f << 'foo' }
687
+ snooze
688
+ f.setup_raw
689
+ assert_equal Thread.current, f.thread
690
+ assert_nil f.parent
691
+
692
+ f.schedule
693
+ f << 'bar'
694
+ snooze
695
+ assert_equal ['bar'], buffer
696
+ end
676
697
  end
677
698
 
678
699
  class MailboxTest < MiniTest::Test
@@ -956,76 +977,3 @@ class RestartTest < MiniTest::Test
956
977
  assert_equal [f, 'foo', 'bar', :done, f2, 'baz', 42, :done], buffer
957
978
  end
958
979
  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
@@ -121,8 +121,47 @@ class MoveOnAfterTest < MiniTest::Test
121
121
  assert t1 - t0 < 0.02
122
122
  assert_equal :bar, v
123
123
  end
124
+
125
+ def test_move_on_after_without_block
126
+ t0 = Time.now
127
+ f = move_on_after(0.01, with_value: 'foo')
128
+ assert_kind_of Fiber, f
129
+ assert_equal Fiber.current, f.parent
130
+ v = sleep 1
131
+ t1 = Time.now
132
+ assert t1 - t0 < 0.02
133
+ assert_equal 'foo', v
134
+ end
135
+ end
136
+
137
+ class CancelAfterTest < MiniTest::Test
138
+ def test_cancel_after
139
+ t0 = Time.now
140
+
141
+ assert_raises Polyphony::Cancel do
142
+ cancel_after(0.01) do
143
+ sleep 1
144
+ :foo
145
+ end
146
+ end
147
+ t1 = Time.now
148
+ assert t1 - t0 < 0.02
149
+ end
150
+
151
+ def test_cancel_after_without_block
152
+ t0 = Time.now
153
+ f = cancel_after(0.01)
154
+ assert_kind_of Fiber, f
155
+ assert_equal Fiber.current, f.parent
156
+ assert_raises Polyphony::Cancel do
157
+ sleep 1
158
+ end
159
+ t1 = Time.now
160
+ assert t1 - t0 < 0.02
161
+ end
124
162
  end
125
163
 
164
+
126
165
  class SpinLoopTest < MiniTest::Test
127
166
  def test_spin_loop
128
167
  buffer = []
@@ -4,20 +4,18 @@ require_relative 'helper'
4
4
 
5
5
  class KernelTest < MiniTest::Test
6
6
  def test_system_method
7
+ fn = '/tmp/test_system_method'
8
+ FileUtils.rm(fn) rescue nil
9
+
7
10
  counter = 0
8
11
  timer = spin { throttled_loop(200) { counter += 1 } }
9
12
 
10
13
  system('sleep 0.01')
11
14
  assert(counter >= 2)
12
15
 
13
- i, o = IO.pipe
14
- orig_stdout = $stdout
15
- $stdout = o
16
- system('echo "hello"')
17
- o.close
18
- assert_equal "hello\n", i.read
16
+ system('echo "hello" > ' + fn)
17
+ assert_equal "hello\n", IO.read(fn)
19
18
  ensure
20
- $stdout = orig_stdout
21
19
  timer&.stop
22
20
  end
23
21
 
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ class ProcessSupervisionTest < MiniTest::Test
6
+ def test_process_supervisor_with_block
7
+ i, o = IO.pipe
8
+
9
+ f = spin do
10
+ Polyphony.watch_process do
11
+ i.close
12
+ sleep 5
13
+ ensure
14
+ o << 'foo'
15
+ o.close
16
+ end
17
+ supervise(on_error: :restart)
18
+ end
19
+
20
+ sleep 0.05
21
+ f.terminate
22
+ f.await
23
+
24
+ o.close
25
+ msg = i.read
26
+ i.close
27
+ assert_equal 'foo', msg
28
+ end
29
+
30
+ def test_process_supervisor_with_cmd
31
+ fn = '/tmp/test_process_supervisor_with_cmd'
32
+ FileUtils.rm(fn) rescue nil
33
+
34
+ f = spin do
35
+ Polyphony.watch_process("echo foo >> #{fn}")
36
+ supervise(on_error: :restart)
37
+ end
38
+
39
+ sleep 0.05
40
+ f.terminate
41
+ f.await
42
+
43
+ assert_equal "foo\n", IO.read(fn)
44
+
45
+ end
46
+ end
@@ -44,11 +44,10 @@ class SignalTrapTest < Minitest::Test
44
44
  i.close
45
45
  spin do
46
46
  spin do
47
- sleep 1
47
+ sleep 5
48
48
  rescue ::Interrupt => e
49
- # the signal will be trapped in the context of this fiber
49
+ # the signal should be raised only in the main fiber
50
50
  o.puts "1-interrupt"
51
- raise e
52
51
  end.await
53
52
  end.await
54
53
  rescue ::Interrupt => e
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+
5
+ class SuperviseTest < MiniTest::Test
6
+ def test_supervise
7
+ p = spin { supervise }
8
+ snooze
9
+ f1 = p.spin { receive }
10
+ f2 = p.spin { receive }
11
+
12
+ snooze
13
+ assert_equal p.state, :waiting
14
+ f1 << 'foo'
15
+ f1.await
16
+ snooze
17
+
18
+ assert_equal :waiting, p.state
19
+ assert_equal :waiting, f2.state
20
+
21
+ f2 << 'bar'
22
+ f2.await
23
+ snooze
24
+
25
+ assert_equal :waiting, p.state
26
+ end
27
+
28
+ def test_supervise_with_restart
29
+ watcher = spin { receive }
30
+ parent = spin { supervise(restart: true, watcher: watcher) }
31
+ snooze
32
+
33
+ buffer = []
34
+ f1 = parent.spin do
35
+ buffer << 'f1'
36
+ end
37
+
38
+ f1.await
39
+ assert_equal ['f1'], buffer
40
+ watcher.await
41
+ assert_equal ['f1', 'f1'], buffer
42
+ end
43
+
44
+ def test_supervise_with_restart_on_error
45
+ parent = spin { supervise(restart: true) }
46
+ snooze
47
+
48
+ buffer = []
49
+ f1 = parent.spin do
50
+ buffer << 'f1'
51
+ buffer << receive
52
+ end
53
+
54
+ snooze
55
+ assert_equal ['f1'], buffer
56
+
57
+ f1.raise 'foo'
58
+
59
+ 3.times { snooze }
60
+
61
+ assert_equal ['f1', 'f1'], buffer
62
+ assert_equal :dead, f1.state
63
+
64
+ # f1 should have been restarted by supervisor
65
+ f1 = parent.children.first
66
+ assert_kind_of Fiber, f1
67
+
68
+ f1 << 'foo'
69
+ f1.await
70
+
71
+ assert_equal ['f1', 'f1', 'foo'], buffer
72
+ end
73
+
74
+ def test_supervisor_termination
75
+ f = nil
76
+ p = spin do
77
+ f = spin { sleep 1 }
78
+ supervise
79
+ end
80
+ sleep 0.01
81
+
82
+ p.terminate
83
+ p.await
84
+
85
+ assert :dead, f.state
86
+ assert :dead, p.state
87
+ end
88
+
89
+ def test_supervisor_termination_with_restart
90
+ f = nil
91
+ p = spin do
92
+ f = spin { sleep 1 }
93
+ supervise(restart: true)
94
+ end
95
+ sleep 0.01
96
+
97
+ p.terminate
98
+ p.await
99
+
100
+ assert :dead, f.state
101
+ assert :dead, p.state
102
+ end
103
+ 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.33'
4
+ version: '0.34'
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-03-08 00:00:00.000000000 Z
11
+ date: 2020-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: modulation
@@ -254,12 +254,30 @@ files:
254
254
  - README.md
255
255
  - Rakefile
256
256
  - TODO.md
257
+ - bin/polyphony-debug
257
258
  - docs/_config.yml
258
259
  - docs/_includes/nav.html
259
260
  - docs/_includes/prevnext.html
260
261
  - docs/_layouts/default.html
261
262
  - docs/_sass/custom/custom.scss
262
263
  - docs/_sass/overrides.scss
264
+ - docs/api-reference.md
265
+ - docs/api-reference/exception.md
266
+ - docs/api-reference/fiber.md
267
+ - docs/api-reference/io.md
268
+ - docs/api-reference/object.md
269
+ - docs/api-reference/polyphony-baseexception.md
270
+ - docs/api-reference/polyphony-cancel.md
271
+ - docs/api-reference/polyphony-moveon.md
272
+ - docs/api-reference/polyphony-net.md
273
+ - docs/api-reference/polyphony-process.md
274
+ - docs/api-reference/polyphony-resourcepool.md
275
+ - docs/api-reference/polyphony-restart.md
276
+ - docs/api-reference/polyphony-terminate.md
277
+ - docs/api-reference/polyphony-threadpool.md
278
+ - docs/api-reference/polyphony-throttler.md
279
+ - docs/api-reference/polyphony.md
280
+ - docs/api-reference/thread.md
263
281
  - docs/assets/img/echo-fibers.svg
264
282
  - docs/assets/img/sleeping-fiber.svg
265
283
  - docs/faq.md
@@ -287,11 +305,15 @@ files:
287
305
  - examples/core/01-spinning-up-fibers.rb
288
306
  - examples/core/02-awaiting-fibers.rb
289
307
  - examples/core/03-interrupting.rb
308
+ - examples/core/forever_sleep.rb
290
309
  - examples/core/xx-at_exit.rb
310
+ - examples/core/xx-caller.rb
291
311
  - examples/core/xx-channels.rb
292
312
  - examples/core/xx-deadlock.rb
293
313
  - examples/core/xx-deferring-an-operation.rb
294
314
  - examples/core/xx-erlang-style-genserver.rb
315
+ - examples/core/xx-exception-backtrace.rb
316
+ - examples/core/xx-fork-spin.rb
295
317
  - examples/core/xx-fork-terminate.rb
296
318
  - examples/core/xx-forking.rb
297
319
  - examples/core/xx-move_on.rb
@@ -304,9 +326,11 @@ files:
304
326
  - examples/core/xx-sleep-forever.rb
305
327
  - examples/core/xx-sleeping.rb
306
328
  - examples/core/xx-snooze-starve.rb
329
+ - examples/core/xx-spin-fork.rb
307
330
  - examples/core/xx-spin_error_backtrace.rb
308
331
  - examples/core/xx-state-machine.rb
309
332
  - examples/core/xx-stop.rb
333
+ - examples/core/xx-supervise-process.rb
310
334
  - examples/core/xx-supervisors.rb
311
335
  - examples/core/xx-thread-selector-sleep.rb
312
336
  - examples/core/xx-thread-selector-snooze.rb
@@ -381,6 +405,7 @@ files:
381
405
  - lib/polyphony/adapters/fs.rb
382
406
  - lib/polyphony/adapters/irb.rb
383
407
  - lib/polyphony/adapters/postgres.rb
408
+ - lib/polyphony/adapters/process.rb
384
409
  - lib/polyphony/adapters/redis.rb
385
410
  - lib/polyphony/adapters/trace.rb
386
411
  - lib/polyphony/core/channel.rb
@@ -410,8 +435,10 @@ files:
410
435
  - test/test_global_api.rb
411
436
  - test/test_io.rb
412
437
  - test/test_kernel.rb
438
+ - test/test_process_supervision.rb
413
439
  - test/test_resource_pool.rb
414
440
  - test/test_signal.rb
441
+ - test/test_supervise.rb
415
442
  - test/test_thread.rb
416
443
  - test/test_thread_pool.rb
417
444
  - test/test_throttler.rb