polyphony 0.43.11 → 0.45.4
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 +8 -1
- data/CHANGELOG.md +40 -0
- data/Gemfile.lock +18 -8
- data/Rakefile +1 -1
- data/TODO.md +22 -9
- data/docs/_posts/2020-07-26-polyphony-0.44.md +77 -0
- data/docs/api-reference/thread.md +1 -1
- data/docs/getting-started/overview.md +14 -14
- data/docs/getting-started/tutorial.md +1 -1
- data/examples/adapters/redis_client.rb +3 -1
- data/examples/adapters/redis_pubsub_perf.rb +11 -8
- data/examples/adapters/sequel_mysql.rb +23 -0
- data/examples/adapters/sequel_mysql_pool.rb +33 -0
- data/examples/adapters/sequel_pg.rb +24 -0
- data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
- data/examples/core/{xx-channels.rb → channels.rb} +0 -0
- data/examples/core/deferring-an-operation.rb +16 -0
- data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
- data/examples/core/{xx-forking.rb → forking.rb} +1 -1
- data/examples/core/handling-signals.rb +11 -0
- data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
- data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
- data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
- data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
- data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
- data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
- data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
- data/examples/core/supervisor.rb +20 -0
- data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
- data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
- data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
- data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
- data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
- data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
- data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
- data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
- data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
- data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
- data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
- data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
- data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
- data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
- data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
- data/examples/io/{xx-irb.rb → irb.rb} +0 -0
- data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
- data/examples/io/{xx-open.rb → open.rb} +0 -0
- data/examples/io/pry.rb +18 -0
- data/examples/io/rack_server.rb +71 -0
- data/examples/io/raw.rb +14 -0
- data/examples/io/reline.rb +18 -0
- data/examples/io/{xx-system.rb → system.rb} +1 -1
- data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
- data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
- data/examples/io/tunnel.rb +6 -1
- data/examples/io/{xx-zip.rb → zip.rb} +0 -0
- data/examples/performance/fiber_transfer.rb +2 -1
- data/examples/performance/fs_read.rb +5 -6
- data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
- data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
- data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
- data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
- data/examples/performance/thread_pool_perf.rb +6 -7
- data/ext/polyphony/backend.h +40 -0
- data/ext/polyphony/event.c +3 -3
- data/ext/polyphony/extconf.rb +1 -1
- data/ext/polyphony/fiber.c +66 -6
- data/ext/polyphony/{libev_agent.c → libev_backend.c} +237 -238
- data/ext/polyphony/polyphony.c +3 -3
- data/ext/polyphony/polyphony.h +15 -20
- data/ext/polyphony/polyphony_ext.c +3 -4
- data/ext/polyphony/queue.c +5 -6
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/thread.c +36 -33
- data/lib/polyphony.rb +26 -39
- data/lib/polyphony/adapters/fs.rb +1 -1
- data/lib/polyphony/adapters/irb.rb +2 -17
- data/lib/polyphony/adapters/mysql2.rb +19 -0
- data/lib/polyphony/adapters/postgres.rb +5 -5
- data/lib/polyphony/adapters/process.rb +2 -5
- data/lib/polyphony/adapters/readline.rb +17 -0
- data/lib/polyphony/adapters/redis.rb +1 -1
- data/lib/polyphony/adapters/sequel.rb +45 -0
- data/lib/polyphony/core/exceptions.rb +11 -0
- data/lib/polyphony/core/global_api.rb +17 -12
- data/lib/polyphony/core/resource_pool.rb +20 -7
- data/lib/polyphony/core/sync.rb +46 -8
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/extensions/core.rb +30 -30
- data/lib/polyphony/extensions/fiber.rb +30 -49
- data/lib/polyphony/extensions/io.rb +60 -16
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +14 -15
- data/lib/polyphony/extensions/thread.rb +6 -5
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +7 -3
- data/test/helper.rb +1 -1
- data/test/{test_agent.rb → test_backend.rb} +22 -22
- data/test/test_fiber.rb +29 -12
- data/test/test_io.rb +59 -1
- data/test/test_kernel.rb +5 -0
- data/test/test_resource_pool.rb +29 -4
- data/test/test_signal.rb +16 -37
- data/test/test_socket.rb +17 -0
- data/test/test_sync.rb +52 -0
- metadata +127 -97
- data/.gitbook.yaml +0 -4
- data/examples/adapters/concurrent-ruby.rb +0 -9
- data/examples/core/04-handling-signals.rb +0 -19
- data/examples/core/xx-agent.rb +0 -102
- data/examples/core/xx-at_exit.rb +0 -29
- data/examples/core/xx-caller.rb +0 -12
- data/examples/core/xx-daemon.rb +0 -14
- data/examples/core/xx-deadlock.rb +0 -8
- data/examples/core/xx-deferring-an-operation.rb +0 -14
- data/examples/core/xx-exception-backtrace.rb +0 -40
- data/examples/core/xx-fork-cleanup.rb +0 -22
- data/examples/core/xx-fork-spin.rb +0 -42
- data/examples/core/xx-fork-terminate.rb +0 -27
- data/examples/core/xx-move_on.rb +0 -23
- data/examples/core/xx-queue-async.rb +0 -120
- data/examples/core/xx-readpartial.rb +0 -18
- data/examples/core/xx-signals.rb +0 -16
- data/examples/core/xx-sleep-forever.rb +0 -9
- data/examples/core/xx-sleeping.rb +0 -25
- data/examples/core/xx-snooze-starve.rb +0 -16
- data/examples/core/xx-spin-fork.rb +0 -49
- data/examples/core/xx-state-machine.rb +0 -51
- data/examples/core/xx-stop.rb +0 -20
- data/examples/core/xx-supervisors.rb +0 -21
- data/examples/core/xx-thread-selector-sleep.rb +0 -51
- data/examples/core/xx-thread-selector-snooze.rb +0 -46
- data/examples/core/xx-thread-snooze.rb +0 -34
- data/examples/core/xx-timer-gc.rb +0 -17
- data/examples/core/xx-trace.rb +0 -79
- data/examples/performance/xx-array.rb +0 -11
- data/examples/performance/xx-fiber-switch.rb +0 -9
- data/examples/performance/xx-snooze.rb +0 -15
- data/examples/xx-spin.rb +0 -32
- data/ext/polyphony/agent.h +0 -41
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 52f8ebf1104d921c9e3b0afa0b4605ee8f912eabe8b6264898f23905d2cb6c6f
|
|
4
|
+
data.tar.gz: 38f0f7cd62997ba5681185c3c4859f57d86de875d8292faf67fffa53c7160181
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2429259a2e79757ec879c4c00db8fd8b87302b9e0a61c6ae2ddd5fdb6e1a3a06ac63d551ed33a4c77480e156eb1247a0fab4a263179a60fd2e9a2d3173831a58
|
|
7
|
+
data.tar.gz: 04f58dafb5faf1e21b08fd85d508ceb6e9869b0a69d63c133661a834f169eb750b599639ffdbff474abf7f92bc6bfee3a43b9442c2885a6dd88328657b0e1d36
|
data/.rubocop.yml
CHANGED
|
@@ -81,6 +81,7 @@ Lint/SuppressedException:
|
|
|
81
81
|
- examples/**/*.rb
|
|
82
82
|
|
|
83
83
|
Metrics/MethodLength:
|
|
84
|
+
Max: 12
|
|
84
85
|
Exclude:
|
|
85
86
|
- lib/polyphony/http/server/rack.rb
|
|
86
87
|
- lib/polyphony/extensions/io.rb
|
|
@@ -95,6 +96,7 @@ Metrics/ModuleLength:
|
|
|
95
96
|
Metrics/ClassLength:
|
|
96
97
|
Exclude:
|
|
97
98
|
- lib/polyphony/http/server/http1.rb
|
|
99
|
+
- lib/polyphony/extensions/io.rb
|
|
98
100
|
- test/**/*.rb
|
|
99
101
|
- examples/**/*.rb
|
|
100
102
|
|
|
@@ -111,6 +113,7 @@ Style/Documentation:
|
|
|
111
113
|
Exclude:
|
|
112
114
|
- test/**/*.rb
|
|
113
115
|
- examples/**/*.rb
|
|
116
|
+
- lib/polyphony/adapters/**/*.rb
|
|
114
117
|
|
|
115
118
|
Style/FormatString:
|
|
116
119
|
Exclude:
|
|
@@ -172,4 +175,8 @@ Style/RedundantRegexpEscape:
|
|
|
172
175
|
Enabled: true
|
|
173
176
|
|
|
174
177
|
Style/SlicingWithRange:
|
|
175
|
-
Enabled: true
|
|
178
|
+
Enabled: true
|
|
179
|
+
|
|
180
|
+
Style/RaiseArgs:
|
|
181
|
+
Exclude:
|
|
182
|
+
- lib/polyphony/extensions/fiber.rb
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
+
## 0.45.4
|
|
2
|
+
|
|
3
|
+
* Improve signal trapping mechanism
|
|
4
|
+
|
|
5
|
+
## 0.45.3
|
|
6
|
+
|
|
7
|
+
* Don't swallow error in `Process#kill_and_await`
|
|
8
|
+
* Add `Fiber#mailbox` attribute reader
|
|
9
|
+
* Fix bug in `Fiber.await`
|
|
10
|
+
* Implement `IO#getc`, `IO#getbyte`
|
|
11
|
+
|
|
12
|
+
## 0.45.2
|
|
13
|
+
|
|
14
|
+
* Rewrite `Fiber#<<`, `Fiber#await`, `Fiber#receive` in C
|
|
15
|
+
|
|
16
|
+
## 0.45.1
|
|
17
|
+
|
|
18
|
+
* Fix Net::HTTP compatibility
|
|
19
|
+
* Fix fs adapter
|
|
20
|
+
* Improve performance of IO#puts
|
|
21
|
+
* Mutex#synchronize
|
|
22
|
+
* Fix Socket#connect
|
|
23
|
+
* Cleanup code
|
|
24
|
+
* Improve support for Ruby 3 keyword args
|
|
25
|
+
|
|
26
|
+
## 0.45.0
|
|
27
|
+
|
|
28
|
+
* Cleanup code
|
|
29
|
+
* Rename `Agent` to `Backend`
|
|
30
|
+
* Implement `Polyphony::ConditionVariable`
|
|
31
|
+
* Fix Kernel.system
|
|
32
|
+
|
|
33
|
+
## 0.44.0 2020-07-25
|
|
34
|
+
|
|
35
|
+
* Fix reentrant `ResourcePool` (#38)
|
|
36
|
+
* Add `ResourcePool#discard!` (#35)
|
|
37
|
+
* Add `Mysql2::Client` and `Sequel::ConnectionPool` adapters (#35)
|
|
38
|
+
* Reimplement `Kernel.trap` using `Fiber#interject`
|
|
39
|
+
* Add `Fiber#interject` for running arbitrary code on arbitrary fibers (#39)
|
|
40
|
+
|
|
1
41
|
## 0.43.11 2020-07-24
|
|
2
42
|
|
|
3
43
|
* Dump uncaught exception info for forked process (#36)
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
polyphony (0.
|
|
4
|
+
polyphony (0.45.4)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
@@ -11,6 +11,7 @@ GEM
|
|
|
11
11
|
ansi (1.5.0)
|
|
12
12
|
ast (2.4.0)
|
|
13
13
|
builder (3.2.4)
|
|
14
|
+
coderay (1.1.3)
|
|
14
15
|
colorator (1.1.0)
|
|
15
16
|
concurrent-ruby (1.1.6)
|
|
16
17
|
docile (1.3.2)
|
|
@@ -22,7 +23,7 @@ GEM
|
|
|
22
23
|
forwardable-extended (2.6.0)
|
|
23
24
|
hiredis (0.6.3)
|
|
24
25
|
http_parser.rb (0.6.0)
|
|
25
|
-
httparty (0.17.
|
|
26
|
+
httparty (0.17.1)
|
|
26
27
|
mime-types (~> 3.0)
|
|
27
28
|
multi_xml (>= 0.5.2)
|
|
28
29
|
i18n (0.9.5)
|
|
@@ -60,11 +61,11 @@ GEM
|
|
|
60
61
|
listen (3.2.1)
|
|
61
62
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
|
62
63
|
rb-inotify (~> 0.9, >= 0.9.10)
|
|
63
|
-
localhost (1.1.4)
|
|
64
64
|
mercenary (0.3.6)
|
|
65
|
+
method_source (1.0.0)
|
|
65
66
|
mime-types (3.3.1)
|
|
66
67
|
mime-types-data (~> 3.2015)
|
|
67
|
-
mime-types-data (3.
|
|
68
|
+
mime-types-data (3.2020.0512)
|
|
68
69
|
minitest (5.13.0)
|
|
69
70
|
minitest-reporters (1.4.2)
|
|
70
71
|
ansi
|
|
@@ -72,16 +73,21 @@ GEM
|
|
|
72
73
|
minitest (>= 5.0)
|
|
73
74
|
ruby-progressbar
|
|
74
75
|
multi_xml (0.6.0)
|
|
76
|
+
mysql2 (0.5.3)
|
|
75
77
|
parallel (1.19.1)
|
|
76
78
|
parser (2.7.0.2)
|
|
77
79
|
ast (~> 2.4.0)
|
|
78
80
|
pathutil (0.16.2)
|
|
79
81
|
forwardable-extended (~> 2.6)
|
|
80
82
|
pg (1.1.4)
|
|
83
|
+
pry (0.13.1)
|
|
84
|
+
coderay (~> 1.1)
|
|
85
|
+
method_source (~> 1.0)
|
|
81
86
|
public_suffix (4.0.3)
|
|
87
|
+
rack (2.2.3)
|
|
82
88
|
rainbow (3.0.0)
|
|
83
89
|
rake (12.3.3)
|
|
84
|
-
rake-compiler (1.
|
|
90
|
+
rake-compiler (1.1.1)
|
|
85
91
|
rake
|
|
86
92
|
rb-fsevent (0.10.3)
|
|
87
93
|
rb-inotify (0.10.1)
|
|
@@ -109,6 +115,7 @@ GEM
|
|
|
109
115
|
sass-listen (4.0.0)
|
|
110
116
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
|
111
117
|
rb-inotify (~> 0.9, >= 0.9.7)
|
|
118
|
+
sequel (5.34.0)
|
|
112
119
|
simplecov (0.17.1)
|
|
113
120
|
docile (~> 1.1)
|
|
114
121
|
json (>= 1.8, < 3)
|
|
@@ -122,19 +129,22 @@ PLATFORMS
|
|
|
122
129
|
DEPENDENCIES
|
|
123
130
|
hiredis (= 0.6.3)
|
|
124
131
|
http_parser.rb (~> 0.6.0)
|
|
125
|
-
httparty (= 0.17.
|
|
132
|
+
httparty (= 0.17.1)
|
|
126
133
|
jekyll (~> 3.8.6)
|
|
127
134
|
jekyll-remote-theme (~> 0.4.1)
|
|
128
135
|
jekyll-seo-tag (~> 2.6.1)
|
|
129
136
|
just-the-docs (~> 0.3.0)
|
|
130
|
-
localhost (= 1.1.4)
|
|
131
137
|
minitest (= 5.13.0)
|
|
132
138
|
minitest-reporters (= 1.4.2)
|
|
139
|
+
mysql2 (= 0.5.3)
|
|
133
140
|
pg (= 1.1.4)
|
|
134
141
|
polyphony!
|
|
135
|
-
|
|
142
|
+
pry (= 0.13.1)
|
|
143
|
+
rack (>= 2.0.8, < 2.3.0)
|
|
144
|
+
rake-compiler (= 1.1.1)
|
|
136
145
|
redis (= 4.1.0)
|
|
137
146
|
rubocop (= 0.85.1)
|
|
147
|
+
sequel (= 5.34.0)
|
|
138
148
|
simplecov (= 0.17.1)
|
|
139
149
|
|
|
140
150
|
BUNDLED WITH
|
data/Rakefile
CHANGED
|
@@ -20,7 +20,7 @@ task :stress_test do
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
task :docs do
|
|
23
|
-
exec 'RUBYOPT=-W0 jekyll serve -s docs -H ec2-
|
|
23
|
+
exec 'RUBYOPT=-W0 jekyll serve -s docs -H ec2-18-156-117-172.eu-central-1.compute.amazonaws.com'
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "**/*.jar", "pkg", "tmp"
|
data/TODO.md
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
|
+
(
|
|
2
|
+
io_uring: some work has been done on an io_uring based scheduler here:
|
|
3
|
+
https://github.com/dsh0416/evt
|
|
4
|
+
|
|
5
|
+
This can serve as a starting point for doing stuff with io_uring
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
0.45.4
|
|
9
|
+
|
|
10
|
+
- Adapter for io/console (what does `IO#raw` do?)
|
|
11
|
+
- Adapter for Pry and IRB (Which fixes #5 and #6)
|
|
12
|
+
- Improve `#supervise`. It does not work as advertised, and seems to exhibit an
|
|
13
|
+
inconsistent behaviour (see supervisor example).
|
|
14
|
+
- Fix backtrace for `Timeout.timeout` API (see timeout example).
|
|
15
|
+
- Check why worker-thread example doesn't work.
|
|
16
|
+
|
|
17
|
+
0.46.0
|
|
18
|
+
|
|
1
19
|
- Debugging
|
|
2
20
|
- Eat your own dogfood: need a good tool to check what's going on when some
|
|
3
21
|
test fails
|
|
4
|
-
- Needs to work with Pry (can write perhaps an extension for pry)
|
|
5
22
|
- First impl in Ruby using `TracePoint` API
|
|
6
23
|
- Mode of operation:
|
|
7
24
|
- Two parts: tracer and controller
|
|
@@ -111,7 +128,7 @@
|
|
|
111
128
|
- discuss using `snooze` for ensuring responsiveness when executing CPU-bound work
|
|
112
129
|
|
|
113
130
|
|
|
114
|
-
## 0.
|
|
131
|
+
## 0.47
|
|
115
132
|
|
|
116
133
|
### Some more API work, more docs
|
|
117
134
|
|
|
@@ -124,13 +141,13 @@
|
|
|
124
141
|
- proceed from there
|
|
125
142
|
|
|
126
143
|
|
|
127
|
-
## 0.
|
|
144
|
+
## 0.48
|
|
128
145
|
|
|
129
146
|
### Sinatra / Sidekiq
|
|
130
147
|
|
|
131
148
|
- Pull out redis/postgres code, put into new `polyphony-xxx` gems
|
|
132
149
|
|
|
133
|
-
## 0.
|
|
150
|
+
## 0.49
|
|
134
151
|
|
|
135
152
|
### Testing && Docs
|
|
136
153
|
|
|
@@ -142,11 +159,7 @@
|
|
|
142
159
|
- `IO.foreach`
|
|
143
160
|
- `Process.waitpid`
|
|
144
161
|
|
|
145
|
-
## 0.
|
|
146
|
-
|
|
147
|
-
### Real IO#gets and IO#read
|
|
148
|
-
|
|
149
|
-
## 0.48 DNS
|
|
162
|
+
## 0.50 DNS
|
|
150
163
|
|
|
151
164
|
### DNS client
|
|
152
165
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Polyphony 0.44.1
|
|
2
|
+
|
|
3
|
+
## More performance, more compatibility, more robustness
|
|
4
|
+
|
|
5
|
+
The last three weeks have been very busy for Polyphony. Since I first presented
|
|
6
|
+
Polyphony here and elsewhere, 17 issues were closed, 10 pull requests were
|
|
7
|
+
merged, and 144 commits were made by 4 different authors. I'm really
|
|
8
|
+
excited about Polyphony and the momentum it seems to be gathering. Your
|
|
9
|
+
reactions have been very positive so far (it even got [tweeted by
|
|
10
|
+
Matz!](https://twitter.com/yukihiro_matz/status/1279289318083715073))
|
|
11
|
+
|
|
12
|
+
I'm even more excited about the contributions Polyphony is starting to get from
|
|
13
|
+
other developers. Thank you [Will](https://github.com/wjordan),
|
|
14
|
+
[Máximo](https://github.com/ElMassimo) and [Trent](https://github.com/misfo) for
|
|
15
|
+
your valuable contributions! Also, the Polyphony project has now got a logo
|
|
16
|
+
designed by my friend [Gérald Morales](https://webocube.com/).
|
|
17
|
+
|
|
18
|
+
I'd like to encourage other developers to get in on the action and start
|
|
19
|
+
contributing by testing Polyphony, creating issues and writing code and
|
|
20
|
+
documentation. Together we can make Polyphony a game-changer for developing
|
|
21
|
+
concurrent apps in Ruby, and finally put to rest the notion that "Ruby is slow"!
|
|
22
|
+
|
|
23
|
+
Since the last public release of Polyphony, we have focused on fixing bugs,
|
|
24
|
+
improving performance and introducing new features that improve the Polyphony
|
|
25
|
+
developer experience. Polyphony 0.44 is up to 20% percent faster than the
|
|
26
|
+
previous release, due notably to a new ring-buffer implementation used by the
|
|
27
|
+
fiber run queue and the `Polyphony::Queue` class, a new `Backend#read_loop` API
|
|
28
|
+
for tighter server loops, and minimizing `fcntl` syscalls when doing I/O. These
|
|
29
|
+
and other minor improvements have resulted in Polyphony first crossing the
|
|
30
|
+
50,000 requests per second threshold for the first time in a minimal [rack
|
|
31
|
+
server
|
|
32
|
+
example](https://github.com/digital-fabric/polyphony/blob/master/examples/io/xx-rack_server.rb).
|
|
33
|
+
|
|
34
|
+
Notable new features include a MySQL adapter, a Sequel adapter, and a new
|
|
35
|
+
`Fiber#interject` API that allows executing arbitrary code on arbitrary fibers.
|
|
36
|
+
|
|
37
|
+
We have also fixed numerous bugs, among which an issue building Polyphony on
|
|
38
|
+
MacOS, problems issuing `Net::HTTP` requests with secure URLs, an issue with
|
|
39
|
+
`YAML.load` and much more...
|
|
40
|
+
|
|
41
|
+
For the full list of changes please consult the [change log](https://github.com/digital-fabric/polyphony/blob/master/CHANGELOG.md).
|
|
42
|
+
|
|
43
|
+
## What's next for Polyphony?
|
|
44
|
+
|
|
45
|
+
The next release of Polyphony will focus on full support IRB and Pry. Being able
|
|
46
|
+
to run operations in the background in IRB and Pry can be very beneficial, most
|
|
47
|
+
of all when developing and when debugging running processes using `binding.pry`
|
|
48
|
+
for example.
|
|
49
|
+
|
|
50
|
+
Subsequent releases will introduce a whole new full-featured debugger for
|
|
51
|
+
fiber-aware concurrent apps, and eventually full support for Sequel, Sinatra,
|
|
52
|
+
Hanami, Sidekiq and other major areas of the Ruby ecosystem.
|
|
53
|
+
|
|
54
|
+
## Tipi - a polyphonic web server for Ruby
|
|
55
|
+
|
|
56
|
+
[Tipi](https://github.com/digital-fabric/tipi) is a new web server for Ruby
|
|
57
|
+
apps. It is intended to be *the* go-to app server for Ruby apps looking for
|
|
58
|
+
robustness, scalability and performance. Tipi already supports HTTP/1, HTTP/2,
|
|
59
|
+
WebSockets and SSL termination. It can currently drive simple Rack apps. In the
|
|
60
|
+
future Tipi will be fully compliant with the Rack specification, and will also
|
|
61
|
+
offer a static file server, a rich configuration and automatic TLS certificates
|
|
62
|
+
(using Let's Encrypt) out of the box.
|
|
63
|
+
|
|
64
|
+
For those wondering about performance, here are some preliminary numbers (see
|
|
65
|
+
disclaimer below):
|
|
66
|
+
|
|
67
|
+
- HTTP, hello world, single process: ~50000 requests/second
|
|
68
|
+
- HTTP, Rack hello world app, single process: ~33000 requests/second
|
|
69
|
+
- HTTP, Rack hello world, 4 worker processes: ~95000 requests/second
|
|
70
|
+
- HTTPS, hello world, single process: ~20000 requests/second
|
|
71
|
+
- HTTPS, hello world, 4 worker processes: ~72000 requests/second
|
|
72
|
+
|
|
73
|
+
Disclaimer: these numbers should be taken with a grain of salt. They do not
|
|
74
|
+
follow any established benchmarking methodology, and may vary significantly. The
|
|
75
|
+
different configurtations were benchmarked using the command: `wrk -d10 -t1 -c10
|
|
76
|
+
"<http|https>://127.0.0.1:1234/"` on the same machine (an `m2.xlarge` instance)
|
|
77
|
+
as the server. In the future Tipi's performance might substantially change. YMMV.
|
|
@@ -12,7 +12,7 @@ Polyphony enhances the core `Thread` class with APIs for switching and
|
|
|
12
12
|
scheduling fibers, and reimplements some of its APIs such as `Thread#raise`
|
|
13
13
|
using fibers which, incidentally, make it safe.
|
|
14
14
|
|
|
15
|
-
Each thread has its own run queue and its own system
|
|
15
|
+
Each thread has its own run queue and its own system backend. While running
|
|
16
16
|
multiple threads does not result in true parallelism in MRI Ruby, sometimes
|
|
17
17
|
multithreading is inevitable, for instance when using third-party gems that
|
|
18
18
|
spawn threads, or when calling blocking APIs that are not fiber-aware.
|
|
@@ -341,25 +341,25 @@ move_on_after(10) { perform_query }
|
|
|
341
341
|
cancel_after(10) { perform_query }
|
|
342
342
|
```
|
|
343
343
|
|
|
344
|
-
## The
|
|
344
|
+
## The Polyphony Backend
|
|
345
345
|
|
|
346
346
|
In order to implement automatic fiber switching when performing blocking
|
|
347
|
-
operations, Polyphony introduces a concept called the *system
|
|
348
|
-
|
|
347
|
+
operations, Polyphony introduces a concept called the *system backend*. The system
|
|
348
|
+
backend is an object having a uniform interface, that performs all blocking
|
|
349
349
|
operations.
|
|
350
350
|
|
|
351
351
|
While a standard event loop-based solution would implement a blocking call
|
|
352
|
-
separately from the fiber scheduling, the system
|
|
352
|
+
separately from the fiber scheduling, the system backend integrates the two to
|
|
353
353
|
create a blocking call that is already knows how to switch and schedule fibers.
|
|
354
354
|
For example, in Polyphony all APIs having to do with reading from files or
|
|
355
|
-
sockets end up calling `Thread.current.
|
|
355
|
+
sockets end up calling `Thread.current.backend.read`, which does all the work.
|
|
356
356
|
|
|
357
357
|
This design offers some major advantages over other designs. It minimizes memory
|
|
358
358
|
allocations, of both Ruby objects and C structures. For example, instead of
|
|
359
359
|
having to allocate libev watchers on the heap and then pass them around, they
|
|
360
360
|
are allocated on the stack instead, which saves up on both memory and CPU cycles.
|
|
361
361
|
|
|
362
|
-
In addition, the
|
|
362
|
+
In addition, the backend interface includes two methods that allow maximizing
|
|
363
363
|
server performance by accepting connections and reading from sockets in a tight
|
|
364
364
|
loop. Here's a naive implementation of an HTTP/1 server:
|
|
365
365
|
|
|
@@ -372,7 +372,7 @@ def handle_client(socket)
|
|
|
372
372
|
reqs = []
|
|
373
373
|
parser.on_message_complete = proc { |env| reqs << { foo: :bar } }
|
|
374
374
|
|
|
375
|
-
Thread.current.
|
|
375
|
+
Thread.current.backend.read_loop(socket) do |data|
|
|
376
376
|
parser << data
|
|
377
377
|
reqs.each { |r| reply(socket, r) }
|
|
378
378
|
reqs.clear
|
|
@@ -388,20 +388,20 @@ end
|
|
|
388
388
|
server = TCPServer.open('0.0.0.0', 1234)
|
|
389
389
|
puts "listening on port 1234"
|
|
390
390
|
|
|
391
|
-
Thread.current.
|
|
391
|
+
Thread.current.backend.accept_loop(server) do |client|
|
|
392
392
|
spin { handle_client(client) }
|
|
393
393
|
end
|
|
394
394
|
```
|
|
395
395
|
|
|
396
|
-
The `#read_loop` and `#accept_loop`
|
|
396
|
+
The `#read_loop` and `#accept_loop` backend methods implement tight loops that
|
|
397
397
|
provide a significant boost to performance (up to +30% better throughput.)
|
|
398
398
|
|
|
399
|
-
Currently, Polyphony includes a single system
|
|
399
|
+
Currently, Polyphony includes a single system backend based on
|
|
400
400
|
[libev](http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod). In the future,
|
|
401
|
-
Polyphony will include other platform-specific system
|
|
402
|
-
|
|
401
|
+
Polyphony will include other platform-specific system backends, such as a Windows
|
|
402
|
+
backend using
|
|
403
403
|
[IOCP](https://docs.microsoft.com/en-us/windows/win32/fileio/i-o-completion-ports),
|
|
404
|
-
or an [io_uring](https://unixism.net/loti/what_is_io_uring.html)
|
|
404
|
+
or an [io_uring](https://unixism.net/loti/what_is_io_uring.html) backend,
|
|
405
405
|
which might be a game-changer for writing highly-concurrent Ruby-based web apps.
|
|
406
406
|
|
|
407
407
|
## Writing Web Apps with Polyphony
|
|
@@ -482,5 +482,5 @@ reach version 1.0. Here are some of the exciting directions we're working on.
|
|
|
482
482
|
|
|
483
483
|
- Support for more core and stdlib APIs
|
|
484
484
|
- More adapters for gems with C-extensions, such as `mysql`, `sqlite3` etc
|
|
485
|
-
- Use `io_uring`
|
|
485
|
+
- Use `io_uring` backend as alternative to the libev backend
|
|
486
486
|
- More concurrency constructs for building highly concurrent applications
|
|
@@ -123,7 +123,7 @@ suspend # The main fiber suspends, waiting for all other work to finish
|
|
|
123
123
|
sleep 1 # The sleeper fiber goes to sleep
|
|
124
124
|
Gyro::Timer.new(1, 0).await # A timer event watcher is setup and yields
|
|
125
125
|
Thread.current.switch_fiber # Polyphony looks for other runnable fibers
|
|
126
|
-
Thread.current.
|
|
126
|
+
Thread.current.backend.poll # With no work left, the event loop is ran
|
|
127
127
|
fiber.schedule # The timer event fires, scheduling the sleeper fiber
|
|
128
128
|
# <= The sleep method returns
|
|
129
129
|
puts "Woke up"
|
|
@@ -6,7 +6,7 @@ require 'json'
|
|
|
6
6
|
|
|
7
7
|
X_SESSIONS = 1000
|
|
8
8
|
X_NODES = 10_000
|
|
9
|
-
X_SUBSCRIPTIONS_PER_SESSION =
|
|
9
|
+
X_SUBSCRIPTIONS_PER_SESSION = 1000
|
|
10
10
|
|
|
11
11
|
$sessions = []
|
|
12
12
|
X_SESSIONS.times do
|
|
@@ -17,8 +17,11 @@ X_SESSIONS.times do
|
|
|
17
17
|
}
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
REDIS_HOST = ENV['REDIS_HOST'] || 'localhost'
|
|
21
|
+
p redis_host: REDIS_HOST
|
|
22
|
+
|
|
20
23
|
spin do
|
|
21
|
-
redis = Redis.new
|
|
24
|
+
redis = Redis.new(host: REDIS_HOST)
|
|
22
25
|
redis.subscribe('events') do |on|
|
|
23
26
|
on.message do |_, message|
|
|
24
27
|
distribute_event(JSON.parse(message, symbolize_names: true))
|
|
@@ -30,18 +33,18 @@ $update_count = 0
|
|
|
30
33
|
|
|
31
34
|
def distribute_event(event)
|
|
32
35
|
$update_count += 1
|
|
33
|
-
|
|
36
|
+
t0 = Time.now
|
|
34
37
|
count = 0
|
|
35
38
|
$sessions.each do |s|
|
|
36
39
|
count += 1 if s[:subscriptions].include?(event[:path])
|
|
37
40
|
end
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
elapsed = Time.now - t0
|
|
42
|
+
rate = X_SESSIONS / elapsed
|
|
43
|
+
puts "elapsed: #{elapsed} (#{rate}/s)" if $update_count % 100 == 0
|
|
41
44
|
end
|
|
42
45
|
|
|
43
46
|
spin do
|
|
44
|
-
redis = Redis.new
|
|
47
|
+
redis = Redis.new(host: REDIS_HOST)
|
|
45
48
|
throttled_loop(1000) do
|
|
46
49
|
redis.publish('events', { path: "node#{rand(X_NODES)}" }.to_json)
|
|
47
50
|
end
|
|
@@ -60,7 +63,7 @@ spin do
|
|
|
60
63
|
end
|
|
61
64
|
end
|
|
62
65
|
|
|
63
|
-
trap(
|
|
66
|
+
trap('SIGINT') do
|
|
64
67
|
puts 'bye...'
|
|
65
68
|
exit!
|
|
66
69
|
end
|