polyphony 0.99.4 → 0.99.6
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/.rubocop.yml +11 -0
- data/.yardopts +0 -2
- data/README.md +1 -1
- data/docs/readme.md +1 -1
- data/docs/tutorial.md +2 -2
- data/examples/pipes/gzip_http_server.rb +2 -2
- data/examples/pipes/http_server.rb +1 -1
- data/examples/pipes/tcp_proxy.rb +1 -1
- data/ext/polyphony/backend_common.c +4 -4
- data/ext/polyphony/backend_io_uring.c +8 -8
- data/ext/polyphony/backend_libev.c +5 -5
- data/ext/polyphony/fiber.c +33 -42
- data/ext/polyphony/io_extensions.c +50 -37
- data/ext/polyphony/pipe.c +6 -20
- data/ext/polyphony/polyphony.c +72 -144
- data/ext/polyphony/queue.c +23 -63
- data/ext/polyphony/thread.c +4 -13
- data/lib/polyphony/adapters/process.rb +2 -5
- data/lib/polyphony/adapters/sequel.rb +2 -2
- data/lib/polyphony/core/debug.rb +1 -4
- data/lib/polyphony/core/exceptions.rb +1 -5
- data/lib/polyphony/core/resource_pool.rb +7 -8
- data/lib/polyphony/core/sync.rb +5 -8
- data/lib/polyphony/core/thread_pool.rb +3 -10
- data/lib/polyphony/core/throttler.rb +1 -5
- data/lib/polyphony/core/timer.rb +23 -30
- data/lib/polyphony/extensions/fiber.rb +513 -543
- data/lib/polyphony/extensions/io.rb +5 -14
- data/lib/polyphony/extensions/object.rb +283 -2
- data/lib/polyphony/extensions/openssl.rb +5 -26
- data/lib/polyphony/extensions/pipe.rb +6 -17
- data/lib/polyphony/extensions/socket.rb +24 -118
- data/lib/polyphony/extensions/thread.rb +3 -18
- data/lib/polyphony/extensions/timeout.rb +0 -1
- data/lib/polyphony/net.rb +5 -9
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +2 -6
- data/test/test_io.rb +221 -221
- data/test/test_socket.rb +3 -3
- data/test/test_trace.rb +2 -2
- metadata +5 -9
- data/docs/index.md +0 -94
- data/docs/link_rewriter.rb +0 -17
- data/docs/main-concepts/index.md +0 -9
- data/lib/polyphony/core/global_api.rb +0 -309
- /data/{assets → docs/assets}/echo-fibers.svg +0 -0
- /data/{assets → docs/assets}/polyphony-logo.png +0 -0
- /data/{assets → docs/assets}/sleeping-fiber.svg +0 -0
data/test/test_socket.rb
CHANGED
@@ -199,7 +199,7 @@ class TCPSocketWithRawBufferTest < MiniTest::Test
|
|
199
199
|
[port, server]
|
200
200
|
rescue Errno::EADDRINUSE
|
201
201
|
retry
|
202
|
-
end
|
202
|
+
end
|
203
203
|
|
204
204
|
def setup
|
205
205
|
super
|
@@ -337,13 +337,13 @@ class SSLSocketTest < MiniTest::Test
|
|
337
337
|
def test_ssl_accept_loop
|
338
338
|
authority = Localhost::Authority.fetch
|
339
339
|
server_ctx = authority.server_context
|
340
|
-
|
340
|
+
|
341
341
|
opts = {
|
342
342
|
reuse_addr: true,
|
343
343
|
dont_linger: true,
|
344
344
|
secure_context: server_ctx
|
345
345
|
}
|
346
|
-
|
346
|
+
|
347
347
|
port = rand(10001..39999)
|
348
348
|
server = Polyphony::Net.tcp_listen('127.0.0.1', port, opts)
|
349
349
|
f = spin do
|
data/test/test_trace.rb
CHANGED
@@ -49,7 +49,7 @@ class TraceTest < MiniTest::Test
|
|
49
49
|
sleep 0
|
50
50
|
|
51
51
|
Thread.backend.trace_proc = nil
|
52
|
-
|
52
|
+
|
53
53
|
assert_equal [
|
54
54
|
[:spin, f],
|
55
55
|
[:schedule, f, nil, false],
|
@@ -143,7 +143,7 @@ class TraceTest < MiniTest::Test
|
|
143
143
|
}
|
144
144
|
}
|
145
145
|
receive
|
146
|
-
|
146
|
+
|
147
147
|
Polyphony::Trace.start_event_firehose { |e| receiver << e }
|
148
148
|
|
149
149
|
f1 = spin(:f1) do
|
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.99.
|
4
|
+
version: 0.99.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05-
|
11
|
+
date: 2023-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -144,9 +144,6 @@ files:
|
|
144
144
|
- README.md
|
145
145
|
- Rakefile
|
146
146
|
- TODO.md
|
147
|
-
- assets/echo-fibers.svg
|
148
|
-
- assets/polyphony-logo.png
|
149
|
-
- assets/sleeping-fiber.svg
|
150
147
|
- bin/pdbg
|
151
148
|
- bin/polyphony-debug
|
152
149
|
- bin/stress.rb
|
@@ -154,15 +151,15 @@ files:
|
|
154
151
|
- docs/_user-guide/all-about-timers.md
|
155
152
|
- docs/_user-guide/index.md
|
156
153
|
- docs/_user-guide/web-server.md
|
154
|
+
- docs/assets/echo-fibers.svg
|
155
|
+
- docs/assets/polyphony-logo.png
|
156
|
+
- docs/assets/sleeping-fiber.svg
|
157
157
|
- docs/concurrency.md
|
158
158
|
- docs/design-principles.md
|
159
159
|
- docs/exception-handling.md
|
160
160
|
- docs/extending.md
|
161
161
|
- docs/faq.md
|
162
162
|
- docs/fiber-scheduling.md
|
163
|
-
- docs/index.md
|
164
|
-
- docs/link_rewriter.rb
|
165
|
-
- docs/main-concepts/index.md
|
166
163
|
- docs/overview.md
|
167
164
|
- docs/readme.md
|
168
165
|
- docs/tutorial.md
|
@@ -335,7 +332,6 @@ files:
|
|
335
332
|
- lib/polyphony/core/channel.rb
|
336
333
|
- lib/polyphony/core/debug.rb
|
337
334
|
- lib/polyphony/core/exceptions.rb
|
338
|
-
- lib/polyphony/core/global_api.rb
|
339
335
|
- lib/polyphony/core/resource_pool.rb
|
340
336
|
- lib/polyphony/core/sync.rb
|
341
337
|
- lib/polyphony/core/thread_pool.rb
|
data/docs/index.md
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
---
|
2
|
-
layout: page
|
3
|
-
title: Home
|
4
|
-
nav_order: 1
|
5
|
-
permalink: /
|
6
|
-
next_title: Installing Polyphony
|
7
|
-
---
|
8
|
-
|
9
|
-
<p align="center"><img src="{{ 'polyphony-logo.png' | absolute_url }}" /></p>
|
10
|
-
|
11
|
-
# Polyphony
|
12
|
-
{:.text-center .logo-title}
|
13
|
-
|
14
|
-
## Fine-grained concurrency for Ruby
|
15
|
-
{:.text-center .logo-title}
|
16
|
-
|
17
|
-
Polyphony is a library for building concurrent applications in Ruby. Polyphony
|
18
|
-
implements a comprehensive
|
19
|
-
[fiber](https://ruby-doc.org/core-2.5.1/Fiber.html)-based concurrency model,
|
20
|
-
using [libev](https://github.com/enki/libev) as a high-performance event reactor
|
21
|
-
for I/O, timers, and other asynchronous events.
|
22
|
-
|
23
|
-
[Overview](getting-started/overview){: .btn .btn-green .text-gamma }
|
24
|
-
[Take the tutorial](getting-started/tutorial){: .btn .btn-blue .text-gamma }
|
25
|
-
[Source code](https://github.com/digital-fabric/polyphony){: .btn .btn-purple .text-gamma target="_blank" }
|
26
|
-
{:.text-center .mt-6 .h-align-center }
|
27
|
-
|
28
|
-
## Focused on Developer Happiness
|
29
|
-
|
30
|
-
Polyphony is designed to make concurrent Ruby programming feel natural and
|
31
|
-
fluent. The Polyphony API is easy to use, easy to understand, and above all
|
32
|
-
idiomatic.
|
33
|
-
|
34
|
-
## Optimized for High Performance
|
35
|
-
|
36
|
-
Polyphony offers high performance for I/O bound Ruby apps. Distributing
|
37
|
-
concurrent operations over fibers, instead of threads or processes, minimizes
|
38
|
-
memory consumption and reduces the cost of context-switching.
|
39
|
-
|
40
|
-
## Designed for Interoperability
|
41
|
-
|
42
|
-
With Polyphony you can use any of the stock Ruby classes and modules like `IO`,
|
43
|
-
`Process`, `Socket` and `OpenSSL` in a concurrent multi-fiber environment. In
|
44
|
-
addition, Polyphony provides a structured model for exception handling that
|
45
|
-
builds on and enhances Ruby's exception handling system.
|
46
|
-
|
47
|
-
## A Growing Ecosystem
|
48
|
-
|
49
|
-
Polyphony includes a full-blown HTTP server implementation with integrated
|
50
|
-
support for HTTP 2, WebSockets, TLS/SSL termination and more. Polyphony also
|
51
|
-
provides fiber-aware adapters for connecting to PostgreSQL and Redis. More
|
52
|
-
adapters are being developed.
|
53
|
-
|
54
|
-
## Features
|
55
|
-
|
56
|
-
* Co-operative scheduling of concurrent tasks using Ruby fibers.
|
57
|
-
* High-performance event reactor for handling I/O events and timers.
|
58
|
-
* Natural, sequential programming style that makes it easy to reason about
|
59
|
-
concurrent code.
|
60
|
-
* Abstractions and constructs for controlling the execution of concurrent code:
|
61
|
-
supervisors, throttling, resource pools etc.
|
62
|
-
* Code can use native networking classes and libraries, growing support for
|
63
|
-
third-party gems such as `pg` and `redis`.
|
64
|
-
* Use stdlib classes such as `TCPServer` and `TCPSocket` and `Net::HTTP`.
|
65
|
-
* Competitive performance and scalability characteristics, in terms of both
|
66
|
-
throughput and memory consumption.
|
67
|
-
|
68
|
-
## Prior Art
|
69
|
-
|
70
|
-
Polyphony draws inspiration from the following, in no particular order:
|
71
|
-
|
72
|
-
* [nio4r](https://github.com/socketry/nio4r/) and
|
73
|
-
[async](https://github.com/socketry/async) (Polyphony's C-extension code
|
74
|
-
started as a spinoff of
|
75
|
-
[nio4r's](https://github.com/socketry/nio4r/tree/master/ext))
|
76
|
-
* The [go scheduler](https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part2.html)
|
77
|
-
* [EventMachine](https://github.com/eventmachine/eventmachine)
|
78
|
-
* [Trio](https://trio.readthedocs.io/)
|
79
|
-
* [Erlang supervisors](http://erlang.org/doc/man/supervisor.html) (and actually,
|
80
|
-
Erlang in general)
|
81
|
-
|
82
|
-
## Developer Resources
|
83
|
-
|
84
|
-
* [Tutorial](getting-started/tutorial)
|
85
|
-
* [Main Concepts](main-concepts/concurrency/)
|
86
|
-
* [User Guide](user-guide/all-about-timers/)
|
87
|
-
* [API Reference](api-reference/exception/)
|
88
|
-
* [Examples](https://github.com/digital-fabric/polyphony/tree/9e0f3b09213156bdf376ef33684ef267517f06e8/examples/README.md)
|
89
|
-
|
90
|
-
## Contributing to Polyphony
|
91
|
-
|
92
|
-
Issues and pull requests will be gladly accepted. Please use the [Polyphony git
|
93
|
-
repository](https://github.com/digital-fabric/polyphony) as your primary point
|
94
|
-
of departure for contributing.
|
data/docs/link_rewriter.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'yard'
|
2
|
-
|
3
|
-
# shamelessly copied from https://github.com/troessner/reek/blob/master/docs/yard_plugin.rb
|
4
|
-
|
5
|
-
# Template helper to modify processing of links in HTML generated from our
|
6
|
-
# markdown files.
|
7
|
-
module LocalLinkHelper
|
8
|
-
# Rewrites links to (assumed local) markdown files so they're processed as
|
9
|
-
# {file: } directives.
|
10
|
-
def resolve_links(text)
|
11
|
-
text = text.gsub(%r{<a href="(docs/[^"]*.md)">([^<]*)</a>}, '{file:/\1 \2}')
|
12
|
-
.gsub(%r{<img src="(assets/[^"]*)">}, '{rdoc-image:/\1}')
|
13
|
-
super text
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
YARD::Templates::Template.extra_includes << LocalLinkHelper
|
data/docs/main-concepts/index.md
DELETED
@@ -1,309 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative './throttler'
|
4
|
-
|
5
|
-
module Polyphony
|
6
|
-
|
7
|
-
# Global API methods to be included in `::Object`
|
8
|
-
module GlobalAPI
|
9
|
-
|
10
|
-
# Spins up a fiber that will run the given block after sleeping for the
|
11
|
-
# given delay.
|
12
|
-
#
|
13
|
-
# @param interval [Number] delay in seconds before running the given block
|
14
|
-
# @yield [] block to run
|
15
|
-
# @return [Fiber] spun fiber
|
16
|
-
def after(interval, &block)
|
17
|
-
spin do
|
18
|
-
sleep interval
|
19
|
-
block.()
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# call-seq:
|
24
|
-
# cancel_after(interval) { ... }
|
25
|
-
# cancel_after(interval, with_exception: exception) { ... }
|
26
|
-
# cancel_after(interval, with_exception: [klass, message]) { ... }
|
27
|
-
# cancel_after(interval) { |timeout| ... }
|
28
|
-
# cancel_after(interval, with_exception: exception) { |timeout| ... }
|
29
|
-
# cancel_after(interval, with_exception: [klass, message]) { |timeout| ... }
|
30
|
-
#
|
31
|
-
# Runs the given block after setting up a cancellation timer for
|
32
|
-
# cancellation. If the cancellation timer elapses, the execution will be
|
33
|
-
# interrupted with an exception defaulting to `Polyphony::Cancel`.
|
34
|
-
#
|
35
|
-
# This method should be used when a timeout should cause an exception to be
|
36
|
-
# propagated down the call stack or up the fiber tree.
|
37
|
-
#
|
38
|
-
# Example of normal use:
|
39
|
-
#
|
40
|
-
# def read_from_io_with_timeout(io)
|
41
|
-
# cancel_after(10) { io.read }
|
42
|
-
# rescue Polyphony::Cancel
|
43
|
-
# nil
|
44
|
-
# end
|
45
|
-
#
|
46
|
-
# The timeout period can be reset by passing a block that takes a single
|
47
|
-
# argument. The block will be provided with the canceller fiber. To reset
|
48
|
-
# the timeout, use `Fiber#reset`, as shown in the following example:
|
49
|
-
#
|
50
|
-
# cancel_after(10) do |timeout|
|
51
|
-
# loop do
|
52
|
-
# msg = socket.gets
|
53
|
-
# timeout.reset
|
54
|
-
# handle_msg(msg)
|
55
|
-
# end
|
56
|
-
# end
|
57
|
-
#
|
58
|
-
# @param interval [Number] timout in seconds
|
59
|
-
# @param with_exception [Class, Exception] exception or exception class
|
60
|
-
# @yield [Fiber] block to execute
|
61
|
-
# @return [any] block's return value
|
62
|
-
def cancel_after(interval, with_exception: Polyphony::Cancel, &block)
|
63
|
-
if block.arity > 0
|
64
|
-
cancel_after_with_optional_reset(interval, with_exception, &block)
|
65
|
-
else
|
66
|
-
Polyphony.backend_timeout(interval, with_exception, &block)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# Spins up a new fiber.
|
71
|
-
#
|
72
|
-
# @param tag [any] optional tag for the new fiber
|
73
|
-
# @yield [any] fiber block
|
74
|
-
# @return [Fiber] new fiber
|
75
|
-
def spin(tag = nil, &block)
|
76
|
-
Fiber.current.spin(tag, caller, &block)
|
77
|
-
end
|
78
|
-
|
79
|
-
# Spins up a new fiber, running the given block inside an infinite loop. If
|
80
|
-
# `rate:` or `interval:` parameters are given, the loop is throttled
|
81
|
-
# accordingly.
|
82
|
-
#
|
83
|
-
# @param tag [any] optional tag for the new fiber
|
84
|
-
# @param rate [Number, nil] loop rate (times per second)
|
85
|
-
# @param interval [Number, nil] interval between consecutive iterations in seconds
|
86
|
-
# @yield [any] code to run
|
87
|
-
# @return [Fiber] new fiber
|
88
|
-
def spin_loop(tag = nil, rate: nil, interval: nil, &block)
|
89
|
-
if rate || interval
|
90
|
-
Fiber.current.spin(tag, caller) do
|
91
|
-
throttled_loop(rate: rate, interval: interval, &block)
|
92
|
-
end
|
93
|
-
else
|
94
|
-
spin_loop_without_throttling(tag, caller, block)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# Runs the given code, then waits for any child fibers of the current fibers
|
99
|
-
# to terminate.
|
100
|
-
#
|
101
|
-
# @yield [any] code to run
|
102
|
-
# @return [any] given block's return value
|
103
|
-
def spin_scope(&block)
|
104
|
-
raise unless block
|
105
|
-
|
106
|
-
spin do
|
107
|
-
result = yield
|
108
|
-
Fiber.current.await_all_children
|
109
|
-
result
|
110
|
-
end.await
|
111
|
-
end
|
112
|
-
|
113
|
-
# Runs the given block in an infinite loop with a regular interval between
|
114
|
-
# consecutive iterations.
|
115
|
-
#
|
116
|
-
# @param interval [Number] interval between consecutive iterations in seconds
|
117
|
-
# @yield [any] block to run
|
118
|
-
# @return [void]
|
119
|
-
def every(interval, &block)
|
120
|
-
Polyphony.backend_timer_loop(interval, &block)
|
121
|
-
end
|
122
|
-
|
123
|
-
# call-seq:
|
124
|
-
# move_on_after(interval) { ... }
|
125
|
-
# move_on_after(interval, with_value: value) { ... }
|
126
|
-
# move_on_after(interval) { |canceller| ... }
|
127
|
-
# move_on_after(interval, with_value: value) { |canceller| ... }
|
128
|
-
#
|
129
|
-
# Runs the given block after setting up a cancellation timer for
|
130
|
-
# cancellation. If the cancellation timer elapses, the execution will be
|
131
|
-
# interrupted with a `Polyphony::MoveOn` exception, which will be rescued,
|
132
|
-
# and with cause the operation to return the given value.
|
133
|
-
#
|
134
|
-
# This method should be used when a timeout is to be handled locally,
|
135
|
-
# without generating an exception that is to propagated down the call stack
|
136
|
-
# or up the fiber tree.
|
137
|
-
#
|
138
|
-
# Example of normal use:
|
139
|
-
#
|
140
|
-
# move_on_after(10) {
|
141
|
-
# sleep 60
|
142
|
-
# 42
|
143
|
-
# } #=> nil
|
144
|
-
#
|
145
|
-
# move_on_after(10, with_value: :oops) {
|
146
|
-
# sleep 60
|
147
|
-
# 42
|
148
|
-
# } #=> :oops
|
149
|
-
#
|
150
|
-
# The timeout period can be reset by passing a block that takes a single
|
151
|
-
# argument. The block will be provided with the canceller fiber. To reset
|
152
|
-
# the timeout, use `Fiber#reset`, as shown in the following example:
|
153
|
-
#
|
154
|
-
# move_on_after(10) do |timeout|
|
155
|
-
# loop do
|
156
|
-
# msg = socket.gets
|
157
|
-
# timeout.reset
|
158
|
-
# handle_msg(msg)
|
159
|
-
# end
|
160
|
-
# end
|
161
|
-
#
|
162
|
-
# @param interval [Number] timout in seconds
|
163
|
-
# @param with_value [any] return value in case of timeout
|
164
|
-
# @yield [Fiber] block to execute
|
165
|
-
# @return [any] block's return value
|
166
|
-
def move_on_after(interval, with_value: nil, &block)
|
167
|
-
if block.arity > 0
|
168
|
-
move_on_after_with_optional_reset(interval, with_value, &block)
|
169
|
-
else
|
170
|
-
Polyphony.backend_timeout(interval, nil, with_value, &block)
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
# Returns the first message from the current fiber's mailbox. If the mailbox
|
175
|
-
# is empty, blocks until a message is available.
|
176
|
-
#
|
177
|
-
# @return [any] received message
|
178
|
-
def receive
|
179
|
-
Fiber.current.receive
|
180
|
-
end
|
181
|
-
|
182
|
-
# Returns all messages currently pending on the current fiber's mailbox.
|
183
|
-
#
|
184
|
-
# @return [Array] array of received messages
|
185
|
-
def receive_all_pending
|
186
|
-
Fiber.current.receive_all_pending
|
187
|
-
end
|
188
|
-
|
189
|
-
# Supervises the current fiber's children. See `Fiber#supervise` for
|
190
|
-
# options.
|
191
|
-
#
|
192
|
-
# @param args [Array] positional parameters
|
193
|
-
# @param opts [Hash] named parameters
|
194
|
-
# @yield [any] given block
|
195
|
-
# @return [void]
|
196
|
-
def supervise(*args, **opts, &block)
|
197
|
-
Fiber.current.supervise(*args, **opts, &block)
|
198
|
-
end
|
199
|
-
|
200
|
-
# Sleeps for the given duration. If the duration is `nil`, sleeps
|
201
|
-
# indefinitely.
|
202
|
-
#
|
203
|
-
# @param duration [Number, nil] duration
|
204
|
-
# @return [void]
|
205
|
-
def sleep(duration = nil)
|
206
|
-
duration ?
|
207
|
-
Polyphony.backend_sleep(duration) : Polyphony.backend_wait_event(true)
|
208
|
-
end
|
209
|
-
|
210
|
-
# call-seq:
|
211
|
-
# throttled_loop(rate) { ... }
|
212
|
-
# throttled_loop(interval: value) { ... }
|
213
|
-
# throttled_loop(rate: value) { ... }
|
214
|
-
# throttled_loop(rate, count: value) { ... }
|
215
|
-
#
|
216
|
-
# Starts a throttled loop with the given rate. If `count:` is given, the
|
217
|
-
# loop is run for the given number of times. Otherwise, the loop is
|
218
|
-
# infinite. The loop rate (times per second) can be given as the rate
|
219
|
-
# parameter. The throttling can also be controlled by providing an
|
220
|
-
# `interval:` or `rate:` named parameter.
|
221
|
-
#
|
222
|
-
# @param rate [Number, nil] loop rate (times per second)
|
223
|
-
# @option opts [Number] :rate loop rate (times per second)
|
224
|
-
# @option opts [Number] :interval loop interval in seconds
|
225
|
-
# @option opts [Number] :count number of iterations (nil for infinite)
|
226
|
-
# @yield [] code to run
|
227
|
-
# @return [void]
|
228
|
-
def throttled_loop(rate = nil, **opts, &block)
|
229
|
-
throttler = Polyphony::Throttler.new(rate || opts)
|
230
|
-
if opts[:count]
|
231
|
-
opts[:count].times { |_i| throttler.(&block) }
|
232
|
-
else
|
233
|
-
while true
|
234
|
-
throttler.(&block)
|
235
|
-
end
|
236
|
-
end
|
237
|
-
rescue LocalJumpError, StopIteration
|
238
|
-
# break called or StopIteration raised
|
239
|
-
end
|
240
|
-
|
241
|
-
private
|
242
|
-
|
243
|
-
# Helper method for performing a `cancel_after` with optional reset.
|
244
|
-
#
|
245
|
-
# @param interval [Number] timeout interval in seconds
|
246
|
-
# @param exception [Exception, Class, Array<class, message>] exception spec
|
247
|
-
# @yield [Fiber] block to run
|
248
|
-
# @return [any] block's return value
|
249
|
-
def cancel_after_with_optional_reset(interval, exception, &block)
|
250
|
-
fiber = Fiber.current
|
251
|
-
canceller = spin do
|
252
|
-
Polyphony.backend_sleep(interval)
|
253
|
-
exception = cancel_exception(exception)
|
254
|
-
exception.raising_fiber = Fiber.current
|
255
|
-
fiber.cancel(exception)
|
256
|
-
end
|
257
|
-
block.call(canceller)
|
258
|
-
ensure
|
259
|
-
canceller.stop
|
260
|
-
end
|
261
|
-
|
262
|
-
# Converts the given exception spec to an exception instance.
|
263
|
-
#
|
264
|
-
# @param exception [Exception, Class, Array<class, message>] exception spec
|
265
|
-
# @return [Exception] exception instance
|
266
|
-
def cancel_exception(exception)
|
267
|
-
case exception
|
268
|
-
when Class then exception.new
|
269
|
-
when Array then exception[0].new(exception[1])
|
270
|
-
else RuntimeError.new(exception)
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
# Helper method for performing `#spin_loop` without throttling. Spins up a
|
275
|
-
# new fiber in which to run the loop.
|
276
|
-
#
|
277
|
-
# @param tag [any] new fiber's tag
|
278
|
-
# @param caller [Array<String>] caller info
|
279
|
-
# @param block [Proc] code to run
|
280
|
-
# @return [void]
|
281
|
-
def spin_loop_without_throttling(tag, caller, block)
|
282
|
-
Fiber.current.spin(tag, caller) do
|
283
|
-
block.call while true
|
284
|
-
rescue LocalJumpError, StopIteration
|
285
|
-
# break called or StopIteration raised
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
# Helper method for performing `#move_on_after` with optional reset.
|
290
|
-
#
|
291
|
-
# @param interval [Number] timeout interval in seconds
|
292
|
-
# @param value [any] return value in case of timeout
|
293
|
-
# @yield [Fiber] code to run
|
294
|
-
# @return [any] return value of given block or timeout value
|
295
|
-
def move_on_after_with_optional_reset(interval, value, &block)
|
296
|
-
fiber = Fiber.current
|
297
|
-
canceller = spin do
|
298
|
-
sleep interval
|
299
|
-
fiber.move_on(value)
|
300
|
-
end
|
301
|
-
block.call(canceller)
|
302
|
-
rescue Polyphony::MoveOn => e
|
303
|
-
e.value
|
304
|
-
ensure
|
305
|
-
canceller.stop
|
306
|
-
end
|
307
|
-
|
308
|
-
end
|
309
|
-
end
|
File without changes
|
File without changes
|
File without changes
|