polyphony 0.20 → 0.21
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/.gitbook.yaml +1 -2
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +1 -1
- data/README.md +18 -449
- data/TODO.md +0 -10
- data/docs/README.md +39 -0
- data/docs/getting-started/installing.md +28 -0
- data/docs/getting-started/tutorial.md +133 -0
- data/docs/summary.md +37 -3
- data/docs/technical-overview/concurrency.md +47 -0
- data/docs/technical-overview/design-principles.md +112 -0
- data/docs/technical-overview/exception-handling.md +34 -41
- data/docs/technical-overview/extending.md +80 -0
- data/docs/technical-overview/faq.md +74 -0
- data/docs/technical-overview/fiber-scheduling.md +23 -52
- data/docs/user-guide/web-server.md +129 -0
- data/examples/core/01-spinning-up-coprocesses.rb +21 -0
- data/examples/core/02-awaiting-coprocesses.rb +18 -0
- data/examples/core/03-interrupting.rb +34 -0
- data/examples/core/04-no-auto-run.rb +18 -0
- data/examples/core/mem-usage.rb +34 -0
- data/examples/core/spin_error.rb +0 -1
- data/examples/core/spin_uncaught_error.rb +0 -1
- data/examples/core/wait_for_signal.rb +14 -0
- data/examples/http/http_server_graceful.rb +25 -0
- data/examples/http/http_server_simple.rb +11 -0
- data/examples/interfaces/redis_pubsub_perf.rb +1 -1
- data/ext/gyro/async.c +4 -40
- data/ext/gyro/child.c +0 -42
- data/ext/gyro/io.c +0 -41
- data/lib/polyphony/core/coprocess.rb +8 -0
- data/lib/polyphony/core/supervisor.rb +29 -10
- data/lib/polyphony/extensions/core.rb +1 -1
- data/lib/polyphony/http/server/http2.rb +20 -4
- data/lib/polyphony/http/server/http2_stream.rb +35 -3
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +17 -5
- data/test/test_async.rb +14 -7
- data/test/test_coprocess.rb +42 -12
- data/test/test_core.rb +26 -0
- data/test/test_io.rb +14 -5
- data/test/test_signal.rb +6 -10
- metadata +17 -5
- data/docs/getting-started/getting-started.md +0 -10
- data/examples/core/spin.rb +0 -14
- data/examples/core/spin_cancel.rb +0 -17
data/ext/gyro/io.c
CHANGED
@@ -10,7 +10,6 @@ struct Gyro_IO {
|
|
10
10
|
struct ev_io ev_io;
|
11
11
|
int active;
|
12
12
|
int event_mask;
|
13
|
-
VALUE callback;
|
14
13
|
VALUE fiber;
|
15
14
|
};
|
16
15
|
|
@@ -23,9 +22,6 @@ static size_t Gyro_IO_size(const void *ptr);
|
|
23
22
|
|
24
23
|
static VALUE Gyro_IO_initialize(VALUE self, VALUE io, VALUE event_mask);
|
25
24
|
|
26
|
-
static VALUE Gyro_IO_start(VALUE self);
|
27
|
-
static VALUE Gyro_IO_stop(VALUE self);
|
28
|
-
|
29
25
|
void Gyro_IO_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents);
|
30
26
|
|
31
27
|
static int Gyro_IO_symbol2event_mask(VALUE sym);
|
@@ -41,8 +37,6 @@ void Init_Gyro_IO() {
|
|
41
37
|
rb_define_alloc_func(cGyro_IO, Gyro_IO_allocate);
|
42
38
|
|
43
39
|
rb_define_method(cGyro_IO, "initialize", Gyro_IO_initialize, 2);
|
44
|
-
rb_define_method(cGyro_IO, "start", Gyro_IO_start, 0);
|
45
|
-
rb_define_method(cGyro_IO, "stop", Gyro_IO_stop, 0);
|
46
40
|
rb_define_method(cGyro_IO, "await", Gyro_IO_await, 0);
|
47
41
|
|
48
42
|
VALUE cIO = rb_const_get(rb_cObject, rb_intern("IO"));
|
@@ -71,9 +65,6 @@ static VALUE Gyro_IO_allocate(VALUE klass) {
|
|
71
65
|
|
72
66
|
static void Gyro_IO_mark(void *ptr) {
|
73
67
|
struct Gyro_IO *io = ptr;
|
74
|
-
if (io->callback != Qnil) {
|
75
|
-
rb_gc_mark(io->callback);
|
76
|
-
}
|
77
68
|
if (io->fiber != Qnil) {
|
78
69
|
rb_gc_mark(io->fiber);
|
79
70
|
}
|
@@ -101,7 +92,6 @@ static VALUE Gyro_IO_initialize(VALUE self, VALUE io_obj, VALUE event_mask) {
|
|
101
92
|
GetGyro_IO(self, io);
|
102
93
|
|
103
94
|
io->event_mask = Gyro_IO_symbol2event_mask(event_mask);
|
104
|
-
io->callback = Qnil;
|
105
95
|
io->fiber = Qnil;
|
106
96
|
io->active = 0;
|
107
97
|
|
@@ -122,42 +112,11 @@ void Gyro_IO_callback(struct ev_loop *ev_loop, struct ev_io *ev_io, int revents)
|
|
122
112
|
io->fiber = Qnil;
|
123
113
|
SCHEDULE_FIBER(fiber, 0);
|
124
114
|
}
|
125
|
-
else if (io->callback != Qnil) {
|
126
|
-
rb_funcall(io->callback, ID_call, 1, INT2NUM(revents));
|
127
|
-
}
|
128
115
|
else {
|
129
116
|
ev_io_stop(EV_DEFAULT, ev_io);
|
130
117
|
}
|
131
118
|
}
|
132
119
|
|
133
|
-
static VALUE Gyro_IO_start(VALUE self) {
|
134
|
-
struct Gyro_IO *io;
|
135
|
-
GetGyro_IO(self, io);
|
136
|
-
|
137
|
-
if (rb_block_given_p()) {
|
138
|
-
io->callback = rb_block_proc();
|
139
|
-
}
|
140
|
-
|
141
|
-
if (!io->active) {
|
142
|
-
ev_io_start(EV_DEFAULT, &io->ev_io);
|
143
|
-
io->active = 1;
|
144
|
-
}
|
145
|
-
|
146
|
-
return self;
|
147
|
-
}
|
148
|
-
|
149
|
-
static VALUE Gyro_IO_stop(VALUE self) {
|
150
|
-
struct Gyro_IO *io;
|
151
|
-
GetGyro_IO(self, io);
|
152
|
-
|
153
|
-
if (io->active) {
|
154
|
-
ev_io_stop(EV_DEFAULT, &io->ev_io);
|
155
|
-
io->active = 0;
|
156
|
-
}
|
157
|
-
|
158
|
-
return self;
|
159
|
-
}
|
160
|
-
|
161
120
|
VALUE Gyro_IO_await(VALUE self) {
|
162
121
|
struct Gyro_IO *io;
|
163
122
|
VALUE ret;
|
@@ -100,6 +100,14 @@ class Coprocess
|
|
100
100
|
@fiber
|
101
101
|
end
|
102
102
|
|
103
|
+
def caller
|
104
|
+
@fiber&.__caller__[2..]
|
105
|
+
end
|
106
|
+
|
107
|
+
def location
|
108
|
+
caller[0]
|
109
|
+
end
|
110
|
+
|
103
111
|
# Kernel.await expects the given argument / block to be a callable, so #call
|
104
112
|
# in fact waits for the coprocess to finish
|
105
113
|
def await
|
@@ -9,12 +9,14 @@ Exceptions = import('./exceptions')
|
|
9
9
|
class Supervisor
|
10
10
|
def initialize
|
11
11
|
@coprocesses = []
|
12
|
+
@pending = []
|
12
13
|
end
|
13
14
|
|
14
15
|
def await(&block)
|
15
16
|
@supervisor_fiber = Fiber.current
|
16
17
|
block&.(self)
|
17
18
|
suspend
|
19
|
+
@coprocesses.map { |cp| cp.result }
|
18
20
|
rescue Exceptions::MoveOn => e
|
19
21
|
e.value
|
20
22
|
ensure
|
@@ -30,12 +32,21 @@ class Supervisor
|
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
def spin(
|
34
|
-
|
35
|
-
@coprocesses <<
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
def spin(coproc = nil, &block)
|
36
|
+
coproc = Coprocess.new(&(coproc || block)) unless coproc.is_a?(Coprocess)
|
37
|
+
@coprocesses << coproc
|
38
|
+
@pending << coproc
|
39
|
+
coproc.when_done { task_completed(coproc) }
|
40
|
+
coproc.run unless coproc.alive?
|
41
|
+
coproc
|
42
|
+
end
|
43
|
+
|
44
|
+
def add(coproc)
|
45
|
+
@coprocesses << coproc
|
46
|
+
@pending << coproc
|
47
|
+
coproc.when_done { task_completed(coproc) }
|
48
|
+
coproc.run unless coproc.alive?
|
49
|
+
coproc
|
39
50
|
end
|
40
51
|
|
41
52
|
def still_running?
|
@@ -51,15 +62,23 @@ class Supervisor
|
|
51
62
|
|
52
63
|
def stop_all_tasks
|
53
64
|
exception = Exceptions::MoveOn.new
|
54
|
-
@
|
65
|
+
@pending.each do |c|
|
55
66
|
c.transfer(exception)
|
56
67
|
end
|
57
68
|
end
|
58
69
|
|
59
70
|
def task_completed(coprocess)
|
60
|
-
return unless @
|
71
|
+
return unless @pending.include?(coprocess)
|
61
72
|
|
62
|
-
@
|
63
|
-
@supervisor_fiber&.transfer if @
|
73
|
+
@pending.delete(coprocess)
|
74
|
+
@supervisor_fiber&.transfer if @pending.empty?
|
64
75
|
end
|
65
76
|
end
|
77
|
+
|
78
|
+
class Coprocess
|
79
|
+
def self.await(*coprocs)
|
80
|
+
supervise do |s|
|
81
|
+
coprocs.each { |cp| s.add cp }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -19,10 +19,16 @@ class Protocol
|
|
19
19
|
@upgrade_headers = upgrade_headers
|
20
20
|
|
21
21
|
@interface = ::HTTP2::Server.new
|
22
|
-
@
|
22
|
+
@connection_fiber = Fiber.current
|
23
|
+
@interface.on(:frame, &method(:send_frame))
|
24
|
+
@streams = {}
|
23
25
|
end
|
24
26
|
|
25
|
-
|
27
|
+
def send_frame(data)
|
28
|
+
@conn << data
|
29
|
+
rescue Exception => e
|
30
|
+
@connection_fiber.transfer e
|
31
|
+
end
|
26
32
|
|
27
33
|
UPGRADE_MESSAGE = <<~HTTP.gsub("\n", "\r\n")
|
28
34
|
HTTP/1.1 101 Switching Protocols
|
@@ -34,6 +40,7 @@ class Protocol
|
|
34
40
|
def upgrade
|
35
41
|
@conn << UPGRADE_MESSAGE
|
36
42
|
settings = @upgrade_headers['HTTP2-Settings']
|
43
|
+
Fiber.current.schedule(nil)
|
37
44
|
@interface.upgrade(settings, @upgrade_headers, '')
|
38
45
|
ensure
|
39
46
|
@upgrade_headers = nil
|
@@ -41,7 +48,7 @@ class Protocol
|
|
41
48
|
|
42
49
|
# Iterates over incoming requests
|
43
50
|
def each(&block)
|
44
|
-
@interface.on(:stream) { |stream|
|
51
|
+
@interface.on(:stream) { |stream| start_stream(stream, &block) }
|
45
52
|
upgrade if @upgrade_headers
|
46
53
|
|
47
54
|
while (data = @conn.readpartial(8192))
|
@@ -51,8 +58,17 @@ class Protocol
|
|
51
58
|
rescue SystemCallError, IOError
|
52
59
|
# ignore
|
53
60
|
ensure
|
54
|
-
|
61
|
+
finalize_client_loop
|
62
|
+
end
|
63
|
+
|
64
|
+
def start_stream(stream, &block)
|
65
|
+
stream = Stream.new(stream, &block)
|
66
|
+
@streams[stream] = true
|
67
|
+
end
|
68
|
+
|
69
|
+
def finalize_client_loop
|
55
70
|
@interface = nil
|
71
|
+
@streams.each_key(&:stop)
|
56
72
|
@conn.close
|
57
73
|
end
|
58
74
|
|
@@ -5,6 +5,7 @@ export_default :StreamHandler
|
|
5
5
|
require 'http/2'
|
6
6
|
|
7
7
|
Request = import './request'
|
8
|
+
Exceptions = import '../../core/exceptions'
|
8
9
|
|
9
10
|
# Manages an HTTP 2 stream
|
10
11
|
class StreamHandler
|
@@ -12,14 +13,38 @@ class StreamHandler
|
|
12
13
|
|
13
14
|
def initialize(stream, &block)
|
14
15
|
@stream = stream
|
15
|
-
@
|
16
|
-
|
17
|
-
|
16
|
+
@calling_fiber = Fiber.current
|
17
|
+
@stream_fiber = Fiber.new { |req| handle_request(req, &block) }
|
18
|
+
|
19
|
+
# Stream callbacks occur on the connection fiber (see HTTP2::Protocol#each).
|
20
|
+
# The request handler is run on a separate fiber for each stream, allowing
|
21
|
+
# concurrent handling of incoming requests on the same HTTP/2 connection.
|
22
|
+
#
|
23
|
+
# The different stream adapter APIs suspend the stream fiber, waiting for
|
24
|
+
# stream callbacks to be called. The callbacks, in turn, transfer control to
|
25
|
+
# the stream fiber, effectively causing the return of the adapter API calls.
|
26
|
+
#
|
27
|
+
# Note: the request handler is run once headers are received. Reading the
|
28
|
+
# request body, if present, is at the discretion of the request handler.
|
29
|
+
# This mirrors the behaviour of the HTTP/1 adapter.
|
18
30
|
stream.on(:headers, &method(:on_headers))
|
19
31
|
stream.on(:data, &method(:on_data))
|
20
32
|
stream.on(:half_close, &method(:on_half_close))
|
21
33
|
end
|
22
34
|
|
35
|
+
def handle_request(request, &block)
|
36
|
+
error = nil
|
37
|
+
block.(request)
|
38
|
+
@calling_fiber.transfer
|
39
|
+
rescue Exceptions::MoveOn
|
40
|
+
# ignore
|
41
|
+
rescue Exception => e
|
42
|
+
error = e
|
43
|
+
ensure
|
44
|
+
@done = true
|
45
|
+
@calling_fiber.transfer error
|
46
|
+
end
|
47
|
+
|
23
48
|
def on_headers(headers)
|
24
49
|
@request = Request.new(headers.to_h, self)
|
25
50
|
@stream_fiber.transfer(@request)
|
@@ -101,4 +126,11 @@ class StreamHandler
|
|
101
126
|
@stream.headers(headers, end_stream: true)
|
102
127
|
end
|
103
128
|
end
|
129
|
+
|
130
|
+
def stop
|
131
|
+
return if @done
|
132
|
+
|
133
|
+
@stream.close
|
134
|
+
@stream_fiber.schedule(Polyphony::MoveOn.new)
|
135
|
+
end
|
104
136
|
end
|
data/lib/polyphony/version.rb
CHANGED
data/lib/polyphony.rb
CHANGED
@@ -32,11 +32,23 @@ module Polyphony
|
|
32
32
|
)
|
33
33
|
|
34
34
|
class << self
|
35
|
-
def trap(sig, ref = false, &callback)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
# def trap(sig, ref = false, &callback)
|
36
|
+
# sig = Signal.list[sig.to_s.upcase] if sig.is_a?(Symbol)
|
37
|
+
# puts "sig = #{sig.inspect}"
|
38
|
+
# watcher = Gyro::Signal.new(sig, &callback)
|
39
|
+
# # Gyro.unref unless ref
|
40
|
+
# watcher
|
41
|
+
# end
|
42
|
+
|
43
|
+
def wait_for_signal(sig)
|
44
|
+
fiber = Fiber.current
|
45
|
+
Gyro.ref
|
46
|
+
trap(sig) do
|
47
|
+
trap(sig, :DEFAULT)
|
48
|
+
Gyro.unref
|
49
|
+
fiber.transfer(sig)
|
50
|
+
end
|
51
|
+
suspend
|
40
52
|
end
|
41
53
|
|
42
54
|
def fork(&block)
|
data/test/test_async.rb
CHANGED
@@ -5,10 +5,12 @@ require_relative 'helper'
|
|
5
5
|
class AsyncTest < MiniTest::Test
|
6
6
|
def test_that_async_watcher_receives_signal_across_threads
|
7
7
|
count = 0
|
8
|
-
a = Gyro::Async.new
|
8
|
+
a = Gyro::Async.new
|
9
|
+
spin {
|
10
|
+
a.await
|
9
11
|
count += 1
|
10
|
-
|
11
|
-
|
12
|
+
}
|
13
|
+
snooze
|
12
14
|
Thread.new do
|
13
15
|
sync_sleep 0.001
|
14
16
|
a.signal!
|
@@ -19,10 +21,15 @@ class AsyncTest < MiniTest::Test
|
|
19
21
|
|
20
22
|
def test_that_async_watcher_coalesces_signals
|
21
23
|
count = 0
|
22
|
-
a = Gyro::Async.new
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
a = Gyro::Async.new
|
25
|
+
coproc = spin {
|
26
|
+
loop {
|
27
|
+
a.await
|
28
|
+
count += 1
|
29
|
+
after(0.01) { coproc.stop }
|
30
|
+
}
|
31
|
+
}
|
32
|
+
snooze
|
26
33
|
Thread.new do
|
27
34
|
sync_sleep 0.001
|
28
35
|
3.times { a.signal! }
|
data/test/test_coprocess.rb
CHANGED
@@ -229,22 +229,52 @@ class CoprocessTest < MiniTest::Test
|
|
229
229
|
assert(raised_error)
|
230
230
|
assert_equal('foo', raised_error.message)
|
231
231
|
end
|
232
|
-
end
|
233
232
|
|
234
|
-
def test_exception_propagation_for_orphan_fiber
|
235
|
-
|
236
|
-
spin do
|
233
|
+
def test_exception_propagation_for_orphan_fiber
|
234
|
+
raised_error = nil
|
237
235
|
spin do
|
238
|
-
|
239
|
-
|
236
|
+
spin do
|
237
|
+
snooze
|
238
|
+
raise 'bar'
|
239
|
+
end
|
240
|
+
end
|
241
|
+
suspend
|
242
|
+
rescue Exception => e
|
243
|
+
raised_error = e
|
244
|
+
ensure
|
245
|
+
assert(raised_error)
|
246
|
+
assert_equal('bar', raised_error.message)
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_await_multiple_coprocesses
|
250
|
+
cp1 = spin { sleep 0.01; :foo }
|
251
|
+
cp2 = spin { sleep 0.01; :bar }
|
252
|
+
cp3 = spin { sleep 0.01; :baz }
|
253
|
+
|
254
|
+
result = Polyphony::Coprocess.await(cp1, cp2, cp3)
|
255
|
+
assert_equal %i{foo bar baz}, result
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_caller
|
259
|
+
location = /^#{__FILE__}:#{__LINE__ + 1}/
|
260
|
+
cp = spin do
|
261
|
+
sleep 0.01
|
262
|
+
end
|
263
|
+
snooze
|
264
|
+
|
265
|
+
caller = cp.caller
|
266
|
+
assert caller[0] =~ location
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_location
|
270
|
+
location = /^#{__FILE__}:#{__LINE__ + 1}/
|
271
|
+
cp = spin do
|
272
|
+
sleep 0.01
|
240
273
|
end
|
274
|
+
snooze
|
275
|
+
|
276
|
+
assert cp.location =~ location
|
241
277
|
end
|
242
|
-
suspend
|
243
|
-
rescue Exception => e
|
244
|
-
raised_error = e
|
245
|
-
ensure
|
246
|
-
assert(raised_error)
|
247
|
-
assert_equal('bar', raised_error.message)
|
248
278
|
end
|
249
279
|
|
250
280
|
class MailboxTest < MiniTest::Test
|
data/test/test_core.rb
CHANGED
@@ -216,3 +216,29 @@ class ExceptionTest < MiniTest::Test
|
|
216
216
|
assert_kind_of RuntimeError, error
|
217
217
|
end
|
218
218
|
end
|
219
|
+
|
220
|
+
class MoveOnAfterTest < MiniTest::Test
|
221
|
+
def test_move_on_after
|
222
|
+
t0 = Time.now
|
223
|
+
v = move_on_after(0.01) do
|
224
|
+
sleep 1
|
225
|
+
:foo
|
226
|
+
end
|
227
|
+
t1 = Time.now
|
228
|
+
|
229
|
+
assert t1 - t0 < 0.02
|
230
|
+
assert_nil v
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_move_on_after_with_value
|
234
|
+
t0 = Time.now
|
235
|
+
v = move_on_after(0.01, with_value: :bar) do
|
236
|
+
sleep 1
|
237
|
+
:foo
|
238
|
+
end
|
239
|
+
t1 = Time.now
|
240
|
+
|
241
|
+
assert t1 - t0 < 0.02
|
242
|
+
assert_equal :bar, v
|
243
|
+
end
|
244
|
+
end
|
data/test/test_io.rb
CHANGED
@@ -6,14 +6,23 @@ class GyroIOTest < MiniTest::Test
|
|
6
6
|
def test_that_reading_works
|
7
7
|
i, o = IO.pipe
|
8
8
|
data = +''
|
9
|
-
|
10
|
-
|
9
|
+
sequence = []
|
10
|
+
watcher = Gyro::IO.new(i, :r)
|
11
|
+
spin {
|
12
|
+
sequence << 1
|
13
|
+
watcher.await
|
14
|
+
sequence << 2
|
11
15
|
i.read_nonblock(8192, data)
|
12
|
-
|
16
|
+
}
|
17
|
+
snooze
|
18
|
+
sequence << 3
|
19
|
+
defer do
|
20
|
+
o << 'hello'
|
21
|
+
sequence << 4
|
13
22
|
end
|
14
|
-
defer { o << 'hello' }
|
15
23
|
suspend
|
16
|
-
assert_equal
|
24
|
+
assert_equal 'hello', data
|
25
|
+
assert_equal [1, 3, 4, 2], sequence
|
17
26
|
end
|
18
27
|
end
|
19
28
|
|
data/test/test_signal.rb
CHANGED
@@ -18,19 +18,15 @@ class SignalTest < MiniTest::Test
|
|
18
18
|
assert_equal(1, count)
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def test_wait_for_signal_api
|
22
22
|
count = 0
|
23
|
-
|
23
|
+
spin do
|
24
|
+
Polyphony.wait_for_signal 'SIGHUP'
|
24
25
|
count += 1
|
25
|
-
w.stop
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
Process.kill(:USR1, Process.pid)
|
32
|
-
end
|
33
|
-
suspend
|
34
|
-
assert_equal(1, count)
|
28
|
+
snooze
|
29
|
+
Process.kill(:HUP, Process.pid)
|
30
|
+
assert_equal 1, count
|
35
31
|
end
|
36
32
|
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.21'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: modulation
|
@@ -213,11 +213,21 @@ files:
|
|
213
213
|
- Rakefile
|
214
214
|
- TODO.md
|
215
215
|
- bin/poly
|
216
|
-
- docs/
|
216
|
+
- docs/README.md
|
217
|
+
- docs/getting-started/installing.md
|
217
218
|
- docs/getting-started/tutorial.md
|
218
219
|
- docs/summary.md
|
220
|
+
- docs/technical-overview/concurrency.md
|
221
|
+
- docs/technical-overview/design-principles.md
|
219
222
|
- docs/technical-overview/exception-handling.md
|
223
|
+
- docs/technical-overview/extending.md
|
224
|
+
- docs/technical-overview/faq.md
|
220
225
|
- docs/technical-overview/fiber-scheduling.md
|
226
|
+
- docs/user-guide/web-server.md
|
227
|
+
- examples/core/01-spinning-up-coprocesses.rb
|
228
|
+
- examples/core/02-awaiting-coprocesses.rb
|
229
|
+
- examples/core/03-interrupting.rb
|
230
|
+
- examples/core/04-no-auto-run.rb
|
221
231
|
- examples/core/cancel.rb
|
222
232
|
- examples/core/channel_echo.rb
|
223
233
|
- examples/core/defer.rb
|
@@ -227,6 +237,7 @@ files:
|
|
227
237
|
- examples/core/fork.rb
|
228
238
|
- examples/core/genserver.rb
|
229
239
|
- examples/core/lock.rb
|
240
|
+
- examples/core/mem-usage.rb
|
230
241
|
- examples/core/move_on.rb
|
231
242
|
- examples/core/move_on_twice.rb
|
232
243
|
- examples/core/move_on_with_ensure.rb
|
@@ -243,8 +254,6 @@ files:
|
|
243
254
|
- examples/core/sleep.rb
|
244
255
|
- examples/core/sleep_spin.rb
|
245
256
|
- examples/core/snooze.rb
|
246
|
-
- examples/core/spin.rb
|
247
|
-
- examples/core/spin_cancel.rb
|
248
257
|
- examples/core/spin_error.rb
|
249
258
|
- examples/core/spin_error_backtrace.rb
|
250
259
|
- examples/core/spin_uncaught_error.rb
|
@@ -258,6 +267,7 @@ files:
|
|
258
267
|
- examples/core/thread_pool.rb
|
259
268
|
- examples/core/throttle.rb
|
260
269
|
- examples/core/timeout.rb
|
270
|
+
- examples/core/wait_for_signal.rb
|
261
271
|
- examples/fs/read.rb
|
262
272
|
- examples/http/config.ru
|
263
273
|
- examples/http/cuba.ru
|
@@ -269,6 +279,8 @@ files:
|
|
269
279
|
- examples/http/http_server.js
|
270
280
|
- examples/http/http_server.rb
|
271
281
|
- examples/http/http_server_forked.rb
|
282
|
+
- examples/http/http_server_graceful.rb
|
283
|
+
- examples/http/http_server_simple.rb
|
272
284
|
- examples/http/http_server_throttled.rb
|
273
285
|
- examples/http/http_ws_server.rb
|
274
286
|
- examples/http/https_raw_client.rb
|
data/examples/core/spin.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bundler/setup'
|
4
|
-
require 'polyphony/auto_run'
|
5
|
-
|
6
|
-
spin do
|
7
|
-
cancel_after(1) do
|
8
|
-
spin do
|
9
|
-
puts 'going to sleep...'
|
10
|
-
sleep(2)
|
11
|
-
ensure
|
12
|
-
puts 'woke up'
|
13
|
-
end.await
|
14
|
-
end
|
15
|
-
rescue Polyphony::Cancel => e
|
16
|
-
puts "got error: #{e}"
|
17
|
-
end
|