polyphony 0.43.10 → 0.45.2
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 +37 -0
- data/Gemfile.lock +16 -6
- data/Rakefile +1 -1
- data/TODO.md +15 -10
- 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/{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} +239 -235
- data/ext/polyphony/polyphony.c +3 -3
- data/ext/polyphony/polyphony.h +15 -23
- data/ext/polyphony/polyphony_ext.c +3 -4
- data/ext/polyphony/queue.c +25 -12
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/thread.c +36 -33
- data/lib/polyphony.rb +25 -38
- 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 -2
- 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 +38 -25
- data/lib/polyphony/extensions/fiber.rb +12 -45
- data/lib/polyphony/extensions/io.rb +45 -12
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +22 -15
- data/lib/polyphony/extensions/thread.rb +6 -5
- data/lib/polyphony/net.rb +2 -1
- 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 +28 -11
- data/test/test_io.rb +17 -1
- data/test/test_kernel.rb +5 -0
- data/test/test_resource_pool.rb +50 -16
- data/test/test_signal.rb +5 -29
- data/test/test_socket.rb +17 -0
- data/test/test_sync.rb +52 -0
- metadata +126 -98
- 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 -39
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a2fa4fa731ff52272d3aed456f7a26751e76c63b4335366919bffaf089bf96dd
|
|
4
|
+
data.tar.gz: 1afe67258c5c73d9cc1082ca238eb358dac0f5b7a975f90a77b4f6de6a23b2a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 175edf315d759f85d2c0d934be36b9fcacd68342206d984ad64f800120a8b65668e9ea81595f47cbbb439402c256b47fde78f0cdad4b42e0c3b1d6ee321135b9
|
|
7
|
+
data.tar.gz: 01cfe1d8b51d60a736adb80062eb22e7983a1879a5491cb7a2e47ec4ad5734e0c8bd8664653870a4393276b42fa912953721658ecff634521a672419c8d3cab6
|
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,40 @@
|
|
|
1
|
+
## 0.45.2
|
|
2
|
+
|
|
3
|
+
* Rewrite `Fiber#<<`, `Fiber#await`, `Fiber#receive` in C
|
|
4
|
+
|
|
5
|
+
## 0.45.1
|
|
6
|
+
|
|
7
|
+
* Fix Net::HTTP compatibility
|
|
8
|
+
* Fix fs adapter
|
|
9
|
+
* Improve performance of IO#puts
|
|
10
|
+
* Mutex#synchronize
|
|
11
|
+
* Fix Socket#connect
|
|
12
|
+
* Cleanup code
|
|
13
|
+
* Improve support for Ruby 3 keyword args
|
|
14
|
+
|
|
15
|
+
## 0.45.0
|
|
16
|
+
|
|
17
|
+
* Cleanup code
|
|
18
|
+
* Rename `Agent` to `Backend`
|
|
19
|
+
* Implement `Polyphony::ConditionVariable`
|
|
20
|
+
* Fix Kernel.system
|
|
21
|
+
|
|
22
|
+
## 0.44.0 2020-07-25
|
|
23
|
+
|
|
24
|
+
* Fix reentrant `ResourcePool` (#38)
|
|
25
|
+
* Add `ResourcePool#discard!` (#35)
|
|
26
|
+
* Add `Mysql2::Client` and `Sequel::ConnectionPool` adapters (#35)
|
|
27
|
+
* Reimplement `Kernel.trap` using `Fiber#interject`
|
|
28
|
+
* Add `Fiber#interject` for running arbitrary code on arbitrary fibers (#39)
|
|
29
|
+
|
|
30
|
+
## 0.43.11 2020-07-24
|
|
31
|
+
|
|
32
|
+
* Dump uncaught exception info for forked process (#36)
|
|
33
|
+
* Add additional socket config options (#37)
|
|
34
|
+
- :reuse_port (`SO_REUSEPORT`)
|
|
35
|
+
- :backlog (listen backlog, default `SOMAXCONN`)
|
|
36
|
+
* Fix possible race condition in Queue#shift (#34)
|
|
37
|
+
|
|
1
38
|
## 0.43.10 2020-07-23
|
|
2
39
|
|
|
3
40
|
* Fix race condition when terminating fibers (#33)
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
polyphony (0.
|
|
4
|
+
polyphony (0.45.2)
|
|
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,13 +73,18 @@ 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
90
|
rake-compiler (1.0.5)
|
|
@@ -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!
|
|
142
|
+
pry (= 0.13.1)
|
|
143
|
+
rack (>= 2.0.8, < 2.3.0)
|
|
135
144
|
rake-compiler (= 1.0.5)
|
|
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,9 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
0.45.2
|
|
2
|
+
|
|
3
|
+
- Adapter for Pry and IRB (Which fixes #5 and #6)
|
|
4
|
+
- Redesign signal handling - the current mechanism is problematic in that it
|
|
5
|
+
does not address signals that do not kill, for instance HUP or USR1.
|
|
6
|
+
- Improve `#supervise`. It does not work as advertised, and seems to exhibit an
|
|
7
|
+
inconsistent behaviour (see supervisor example).
|
|
8
|
+
- Fix backtrace for `Timeout.timeout` API (see timeout example).
|
|
9
|
+
- Check why worker-thread example doesn't work.
|
|
10
|
+
|
|
11
|
+
0.46.0
|
|
2
12
|
|
|
3
13
|
- Debugging
|
|
4
14
|
- Eat your own dogfood: need a good tool to check what's going on when some
|
|
5
15
|
test fails
|
|
6
|
-
- Needs to work with Pry (can write perhaps an extension for pry)
|
|
7
16
|
- First impl in Ruby using `TracePoint` API
|
|
8
17
|
- Mode of operation:
|
|
9
18
|
- Two parts: tracer and controller
|
|
@@ -113,7 +122,7 @@
|
|
|
113
122
|
- discuss using `snooze` for ensuring responsiveness when executing CPU-bound work
|
|
114
123
|
|
|
115
124
|
|
|
116
|
-
## 0.
|
|
125
|
+
## 0.47
|
|
117
126
|
|
|
118
127
|
### Some more API work, more docs
|
|
119
128
|
|
|
@@ -126,13 +135,13 @@
|
|
|
126
135
|
- proceed from there
|
|
127
136
|
|
|
128
137
|
|
|
129
|
-
## 0.
|
|
138
|
+
## 0.48
|
|
130
139
|
|
|
131
140
|
### Sinatra / Sidekiq
|
|
132
141
|
|
|
133
142
|
- Pull out redis/postgres code, put into new `polyphony-xxx` gems
|
|
134
143
|
|
|
135
|
-
## 0.
|
|
144
|
+
## 0.49
|
|
136
145
|
|
|
137
146
|
### Testing && Docs
|
|
138
147
|
|
|
@@ -144,11 +153,7 @@
|
|
|
144
153
|
- `IO.foreach`
|
|
145
154
|
- `Process.waitpid`
|
|
146
155
|
|
|
147
|
-
## 0.
|
|
148
|
-
|
|
149
|
-
### Real IO#gets and IO#read
|
|
150
|
-
|
|
151
|
-
## 0.48 DNS
|
|
156
|
+
## 0.50 DNS
|
|
152
157
|
|
|
153
158
|
### DNS client
|
|
154
159
|
|
|
@@ -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
|