iodine 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +90 -31
- data/examples/redis.ru +2 -3
- data/iodine.gemspec +3 -3
- data/lib/iodine.rb +11 -9
- data/lib/iodine/monkeypatch.rb +17 -12
- data/lib/iodine/version.rb +1 -1
- metadata +20 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ae7877010acc419eed5fe07927ba5bbe3a58c4d
|
4
|
+
data.tar.gz: af9499644636b46887940f5328f0204f1f654e42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30225e2179f074851eeb497a03e57a1d7e142b6f85c367b28efd99a4af3f4648fef1655a0fe599de95c05826931c726d4dc2fc4fa02597efce065b51d380a755
|
7
|
+
data.tar.gz: 9b28f309443e33f15ea48993ba4ff8a74c83580ad2a24957c2678b4bca333f5c50e011673613f13bc7f8f8434366e043b48d648e999a0c44e9518a9e6450370d
|
data/CHANGELOG.md
CHANGED
@@ -8,6 +8,14 @@ Please notice that this change log contains changes for upcoming releases as wel
|
|
8
8
|
|
9
9
|
***
|
10
10
|
|
11
|
+
#### Change log v.0.4.1
|
12
|
+
|
13
|
+
**Fix**: postpone warmup in fear of abuse and collisions when using `fork`. i.e., during warmup, an application might perform actions that conflict with `fork` and worker initialization, such as creating a database connection pool during warmup, or maybe spawning a thread. Now `warmup` is postponed until *after* worker processes are up and running, resulting in a per-process warmup rather than a per-cluster warmup.
|
14
|
+
|
15
|
+
**Fix** move the `rake-compiler` dependency to "development" instead of "runtime". Credit to Luis Lavena (@luislavena) for exposing the issue (#19).
|
16
|
+
|
17
|
+
***
|
18
|
+
|
11
19
|
#### Change log v.0.4.0
|
12
20
|
|
13
21
|
**Braking change**: Some of the API was changed / updated, hopefully simplified.
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# iodine - HTTP / Websocket Server with Pub/Sub support, optimized for Ruby MRI on Linux / BSD
|
2
2
|
[![Logo](https://github.com/boazsegev/iodine/raw/master/logo.png)](https://github.com/boazsegev/iodine)
|
3
3
|
|
4
4
|
[![Build Status](https://travis-ci.org/boazsegev/iodine.svg?branch=master)](https://travis-ci.org/boazsegev/iodine)
|
@@ -6,21 +6,24 @@
|
|
6
6
|
[![Inline docs](http://inch-ci.org/github/boazsegev/iodine.svg?branch=master)](http://www.rubydoc.info/github/boazsegev/iodine/master/frames)
|
7
7
|
[![GitHub](https://img.shields.io/badge/GitHub-Open%20Source-blue.svg)](https://github.com/boazsegev/iodine)
|
8
8
|
|
9
|
-
Iodine is a fast concurrent web server for real-time Ruby applications, with native support for
|
9
|
+
Iodine is a fast concurrent web server for real-time Ruby applications, with native support for:
|
10
10
|
|
11
|
-
|
11
|
+
* Websockets;
|
12
|
+
* Pub/Sub (with optional Redis Pub/Sub scaling);
|
13
|
+
* Static file service (with automatic `gzip` support for pre-compressed versions);
|
14
|
+
* HTTP/1.1 keep-alive and pipelining;
|
15
|
+
* Asynchronous event scheduling and timers;
|
16
|
+
* Client connectivity (attach client sockets to make them evented);
|
17
|
+
* Custom protocol authoring;
|
18
|
+
* and more!
|
12
19
|
|
13
20
|
Iodine is an **evented** framework with a simple API that builds off the low level [C code library facil.io](https://github.com/boazsegev/facil.io) with support for **epoll** and **kqueue** - this means that:
|
14
21
|
|
15
|
-
* Iodine can handle **thousands of concurrent connections** (tested with more then 20K connections)
|
16
|
-
|
17
|
-
That's right, Iodine isn't subject to the 1024 connection limit imposed by native Ruby and `select`/`poll` based applications.
|
18
|
-
|
19
|
-
This makes Iodine ideal for writing HTTP/2 and Websocket servers (which is what started this whole thing).
|
22
|
+
* Iodine can handle **thousands of concurrent connections** (tested with more then 20K connections)!
|
20
23
|
|
21
24
|
* Iodine supports only **Linux/Unix** based systems (i.e. OS X, Ubuntu, FreeBSD etc'), which are ideal for evented IO (while Windows and Solaris are better at IO *completion* events, which are totally different).
|
22
25
|
|
23
|
-
Iodine is a C extension for Ruby, developed for Ruby MRI 2.2.2 and up... it should support the whole Ruby 2.0 MRI family, but Rack requires Ruby 2.2.2, and so
|
26
|
+
Iodine is a C extension for Ruby, developed and optimized for Ruby MRI 2.2.2 and up... it should support the whole Ruby 2.0 MRI family, but Rack requires Ruby 2.2.2, and so iodine matches this requirement.
|
24
27
|
|
25
28
|
## Iodine::Rack == a fast and powerful HTTP + Websockets server with native Pub/Sub
|
26
29
|
|
@@ -28,11 +31,11 @@ Iodine includes a light and fast HTTP and Websocket server written in C that was
|
|
28
31
|
|
29
32
|
With `Iodine.listen2http` it's possible to run multiple HTTP applications in addition to (or instead of) the default `Iodine::Rack` HTTP service.
|
30
33
|
|
31
|
-
Iodine also supports native process cluster Pub/Sub and a native RedisEngins to easily scale
|
34
|
+
Iodine also supports native process cluster Pub/Sub and a native RedisEngins to easily scale iodine's Pub/Sub horizontally.
|
32
35
|
|
33
36
|
### Running the web server
|
34
37
|
|
35
|
-
Using the
|
38
|
+
Using the iodine server is easy, simply add iodine as a gem to your Rack application:
|
36
39
|
|
37
40
|
```ruby
|
38
41
|
gem 'iodine', '~>0.4'
|
@@ -40,7 +43,7 @@ gem 'iodine', '~>0.4'
|
|
40
43
|
|
41
44
|
Iodine will calculate, when possible, a good enough default concurrency model for lightweight applications... this might not fit your application if you use heavier database access or other blocking calls.
|
42
45
|
|
43
|
-
To get the most out of
|
46
|
+
To get the most out of iodine, consider the amount of CPU cores available and the concurrency level the application requires.
|
44
47
|
|
45
48
|
The common model of 16 threads and 4 processes can be easily adopted:
|
46
49
|
|
@@ -52,7 +55,7 @@ bundler exec iodine -p $PORT -t 16 -w 4
|
|
52
55
|
|
53
56
|
Iodine supports an internal static file service that bypasses the Ruby layer and serves static files directly from "C-land".
|
54
57
|
|
55
|
-
This means that
|
58
|
+
This means that iodine won't lock Ruby's GVL when sending static files. The files will be sent directly, allowing for true native concurrency.
|
56
59
|
|
57
60
|
Since the Ruby layer is unaware of these requests, logging can be performed by turning iodine's logger on.
|
58
61
|
|
@@ -86,7 +89,7 @@ Ruby can leverage static file support (if enabled) by using the `X-Sendfile` hea
|
|
86
89
|
|
87
90
|
This allows Ruby to send very large files using a very small memory footprint, as well as (when possible) leveraging the `sendfile` system call.
|
88
91
|
|
89
|
-
i.e. (example `config.ru` for
|
92
|
+
i.e. (example `config.ru` for iodine):
|
90
93
|
|
91
94
|
```ruby
|
92
95
|
app = proc do |env|
|
@@ -108,17 +111,31 @@ run app
|
|
108
111
|
|
109
112
|
Go to [localhost:3000/source](http://localhost:3000/source) to download the `config.ru` file using the `X-Sendfile` extension.
|
110
113
|
|
114
|
+
#### Pre-Compressed assets / files
|
115
|
+
|
116
|
+
Simply `gzip` your static files and iodine will automatically recognize and send the `gz` version if the client (browser) supports the `gzip` transfer-encoding.
|
117
|
+
|
118
|
+
For example, to offer a compressed version of `style.css`, run (in the terminal):
|
119
|
+
|
120
|
+
$ gzip -k -9 style.css
|
121
|
+
|
122
|
+
Now, you will have two files in your folder, `style.css` and `style.css.gz`.
|
123
|
+
|
124
|
+
When a browser that supports compressed encoding (which is most browsers) requests the file, iodine will recognize that a pre-compressed option exists and will prefer the `gzip` compressed version.
|
125
|
+
|
126
|
+
It's as easy as that. No extra code required.
|
127
|
+
|
111
128
|
### Special HTTP `Upgrade` support
|
112
129
|
|
113
|
-
Iodine's HTTP server includes special support for the Upgrade directive using Rack's `env` Hash, allowing the application to focus on services and data while
|
130
|
+
Iodine's HTTP server includes special support for the Upgrade directive using Rack's `env` Hash, allowing the application to focus on services and data while iodine takes care of the network layer.
|
114
131
|
|
115
|
-
Upgrading an HTTP connection can be performed either using
|
132
|
+
Upgrading an HTTP connection can be performed either using iodine's Websocket Protocol support with `env['upgrade.websocket']` or by implementing your own protocol directly over the TCP/IP layer - be it a websocket flavor or something completely different - using `env['upgrade.tcp']`.
|
116
133
|
|
117
134
|
#### Websockets
|
118
135
|
|
119
|
-
When an HTTP Upgrade request is received,
|
136
|
+
When an HTTP Upgrade request is received, iodine will set the Rack Hash's upgrade property to `true`, so that: `env[upgrade.websocket?] == true`
|
120
137
|
|
121
|
-
To "upgrade" the HTTP request to the Websockets protocol, simply provide
|
138
|
+
To "upgrade" the HTTP request to the Websockets protocol, simply provide iodine with a Websocket Callback Object instance or class: `env['upgrade.websocket'] = MyWebsocketClass` or `env['upgrade.websocket'] = MyWebsocketClass.new(args)`
|
122
139
|
|
123
140
|
Iodine will adopt the object, providing it with network functionality (methods such as `write`, `each`, `defer` and `close` will become available) and invoke it's callbacks on network events.
|
124
141
|
|
@@ -126,7 +143,7 @@ Here is a simple chatroom example we can run in the terminal (`irb`) or easily p
|
|
126
143
|
|
127
144
|
```ruby
|
128
145
|
require 'iodine'
|
129
|
-
class
|
146
|
+
class WebsocketChat
|
130
147
|
def on_open
|
131
148
|
# Pub/Sub directly to the client (or use a block to process the messages)
|
132
149
|
subscribe channel: :chat
|
@@ -140,7 +157,7 @@ class WebsocketEcho
|
|
140
157
|
end
|
141
158
|
Iodine::Rack.app= Proc.new do |env|
|
142
159
|
if env['upgrade.websocket?'.freeze] && env["HTTP_UPGRADE".freeze] =~ /websocket/i.freeze
|
143
|
-
env['upgrade.websocket'.freeze] =
|
160
|
+
env['upgrade.websocket'.freeze] = WebsocketChat # or: WebsocketChat.new
|
144
161
|
[0,{}, []] # It's possible to set cookies for the response.
|
145
162
|
else
|
146
163
|
[200, {"Content-Length" => "12"}, ["Welcome Home"] ]
|
@@ -157,6 +174,48 @@ Iodine::Rack.public = "www/public"
|
|
157
174
|
Iodine.start
|
158
175
|
```
|
159
176
|
|
177
|
+
#### Native Pub/Sub with *optional* Redis scaling
|
178
|
+
|
179
|
+
Iodine's core, `facil.io` offers a native Pub/Sub implementation. The implementation is totally native to iodine, it covers the whole process cluster and it can be easily scaled by using Redis (which isn't required except for horizontal scaling).
|
180
|
+
|
181
|
+
Here's an example that adds horizontal scaling to the chat application in the previous example, so that Pub/Sub messages are published across many machines at once:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
require 'uri'
|
185
|
+
# initialize the Redis engine for each iodine process.
|
186
|
+
if ENV["REDIS_URL"]
|
187
|
+
uri = URI(ENV["REDIS_URL"])
|
188
|
+
Iodine.default_pubsub = Iodine::PubSub::RedisEngine.new(uri.host, uri.port, 0, uri.password)
|
189
|
+
else
|
190
|
+
puts "* No Redis, it's okay, pub/sub will still run on the whole process cluster."
|
191
|
+
end
|
192
|
+
|
193
|
+
# ... the rest of the application remain unchanged.
|
194
|
+
```
|
195
|
+
|
196
|
+
The new Redis client can also be used for asynchronous Redis command execution. i.e.:
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
if(Iodine.default_pubsub.is_a? Iodine::PubSub::RedisEngine)
|
200
|
+
# Ask Redis about all it's client connections and print out the reply.
|
201
|
+
Iodine.default_pubsub.send("CLIENT LIST") { |reply| puts reply }
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
**Details and Limitations:**
|
206
|
+
|
207
|
+
* Iodine does not use a Hash table for the Pub/Sub channels, it uses a [4 bit trie](https://en.wikipedia.org/wiki/Trie).
|
208
|
+
|
209
|
+
The cost is higher memory consumption per channel and a limitation of 1024 bytes per channel name (shorter names are better).
|
210
|
+
|
211
|
+
The bonus is high lookup times, zero chance of channel conflicts and an optimized preference for shared prefix channels (i.e. "user:1", "user:2"...).
|
212
|
+
|
213
|
+
Another added bonus is pattern publishing (is addition to pattern subscriptions) which isn't available when using Redis (since Redis doesn't support this feature).
|
214
|
+
|
215
|
+
* Iodine's Redis client does *not* support multiple databases. This is both becasue [database scoping is ignored by Redis during pub/sub](https://redis.io/topics/pubsub#database-amp-scoping) and because [Redis Cluster doesn't support multiple databases](https://redis.io/topics/cluster-spec). This indicated that multiple database support just isn't worth the extra effort.
|
216
|
+
|
217
|
+
* The iodine Redis client will use two Redis connections per process (one for subscriptions and the other for publishing and commands). Both connections will be automatically re-established if timeouts or errors occur.
|
218
|
+
|
160
219
|
#### TCP/IP (raw) sockets
|
161
220
|
|
162
221
|
Upgrading to a custom protocol (i.e., in order to implement your own Websocket protocol with special extensions) is performed almost the same way, using `env['upgrade.tcp']`. In the following (terminal) example, we'll use an echo server without direct socket echo:
|
@@ -188,7 +247,7 @@ This design has a number of benefits, some of them related to better IO handling
|
|
188
247
|
|
189
248
|
Iodine::Rack imposes a few restrictions for performance and security reasons, such as that the headers (both sending and receiving) must be less than 8Kb in size. These restrictions shouldn't be an issue and are similar to limitations imposed by Apache.
|
190
249
|
|
191
|
-
Of course, if you still want to use Rack's `hijack` API,
|
250
|
+
Of course, if you still want to use Rack's `hijack` API, iodine will support you - but be aware that you will need to implement your own reactor and thread pool for any sockets you hijack, as well as a socket buffer for non-blocking `write` operations (why do that when you can write a protocol object and have the main reactor manage the socket?).
|
192
251
|
|
193
252
|
### Performance oriented design - but safety first
|
194
253
|
|
@@ -225,13 +284,13 @@ The slower your application code, the more threads you will need to keep the ser
|
|
225
284
|
|
226
285
|
### How does it compare to other servers?
|
227
286
|
|
228
|
-
Personally, after looking around, the only comparable servers are Puma and Passenger, which
|
287
|
+
Personally, after looking around, the only comparable servers are Puma and Passenger, which iodine significantly outperformed on my tests (I didn't test Passenger's enterprise version).
|
229
288
|
|
230
289
|
Since the HTTP and Websocket parsers are written in C (with no RegExp), they're fairly fast.
|
231
290
|
|
232
|
-
Also,
|
291
|
+
Also, iodine's core and parsers are running outside of Ruby's global lock, meaning that they enjoy true concurrency before entering the Ruby layer (your application) - this offers iodine a big advantage over other Ruby servers.
|
233
292
|
|
234
|
-
Another assumption
|
293
|
+
Another assumption iodine makes is that it is behind a load balancer / proxy (which is the normal way Ruby applications are deployed) - this allows iodine to disregard header validity checks (we're not checking for invalid characters) and focus it's resources on other security and performance concerns.
|
235
294
|
|
236
295
|
I recommend benchmarking the performance for yourself using `wrk` or `ab`:
|
237
296
|
|
@@ -254,7 +313,7 @@ end
|
|
254
313
|
run App
|
255
314
|
```
|
256
315
|
|
257
|
-
Then start comparing servers. Here are the settings I used to compare
|
316
|
+
Then start comparing servers. Here are the settings I used to compare iodine and Puma (4 processes, 16 threads):
|
258
317
|
|
259
318
|
```bash
|
260
319
|
$ RACK_ENV=production iodine -p 3000 -t 16 -w 4
|
@@ -264,11 +323,11 @@ $ RACK_ENV=production puma -p 3000 -t 16 -w 4
|
|
264
323
|
```
|
265
324
|
|
266
325
|
|
267
|
-
When benchmarking with `wrk`,
|
326
|
+
When benchmarking with `wrk`, iodine performed significantly better, (~62K req/sec vs. ~44K req/sec) while keeping a lower memory foot print (~60Mb vs. ~111Mb).
|
268
327
|
|
269
|
-
When benchmarking with `ab`, I got different results, where
|
328
|
+
When benchmarking with `ab`, I got different results, where iodine still performed significantly better, (~72K req/sec vs. ~36K req/sec and ~61Mb vs. ~81.6Mb). I suspect the difference between the two benchmarks has to do with system calls to `write`, but I have no real proof.
|
270
329
|
|
271
|
-
Remember to compare the memory footprint after running some requests - it's not just speed that C is helping with, it's also memory management and object pooling (i.e.,
|
330
|
+
Remember to compare the memory footprint after running some requests - it's not just speed that C is helping with, it's also memory management and object pooling (i.e., iodine uses a buffer packet pool management).
|
272
331
|
|
273
332
|
## Can I try before I buy?
|
274
333
|
|
@@ -282,7 +341,7 @@ $ gem install iodine
|
|
282
341
|
|
283
342
|
If building the native C extension fails, please note that some Ruby installations, such as on Ubuntu, require that you separately install the development headers (`ruby.h` and friends). I have no idea why they do that, as you will need the development headers for any native gems you want to install - so hurry up and get them.
|
284
343
|
|
285
|
-
If you have the development headers but still can't compile the
|
344
|
+
If you have the development headers but still can't compile the iodine extension, [open an issue](https://github.com/boazsegev/iodine/issues) with any messages you're getting and I'll be happy to look into it.
|
286
345
|
|
287
346
|
## Mr. Sandman, write me a server
|
288
347
|
|
@@ -330,7 +389,7 @@ But me, I prefer to make sure my development software runs the exact same code a
|
|
330
389
|
|
331
390
|
Also, I don't really understand all the minute details of EventMachine's API, it kept crashing my system every time I reached 1K-2K active connections... I'm sure I just don't know how to use EventMachine, but that's just that.
|
332
391
|
|
333
|
-
Besides, you're here - why not take
|
392
|
+
Besides, you're here - why not take iodine out for a spin and see for yourself?
|
334
393
|
|
335
394
|
## Can I contribute?
|
336
395
|
|
@@ -364,7 +423,7 @@ Here's a few things you can use from this project and they seem to be handy to h
|
|
364
423
|
|
365
424
|
This one is a simple binary tree with a Ruby GC callback. Remember to initialize the Registry (`Registry.init(owner)`) so it's "owned" by some Ruby-land object, this allows it to bridge the two worlds for the GC's mark and sweep.
|
366
425
|
|
367
|
-
I'm attaching it to one of
|
426
|
+
I'm attaching it to one of iodine's library classes, just in-case someone adopts my code and decides the registry should be owned by the global Object class.
|
368
427
|
|
369
428
|
* I was using a POSIX thread pool library ([`libasync.h`](https://github.com/boazsegev/facil.io/blob/master/lib/libasync.c)) until I realized how many issues Ruby has with non-Ruby threads... So now there's a Ruby-thread port for this library at ([`rb-libasync.h`](https://github.com/boazsegev/iodine/blob/master/ext/iodine/rb-libasync.h)).
|
370
429
|
|
data/examples/redis.ru
CHANGED
@@ -8,14 +8,13 @@
|
|
8
8
|
# REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3030 redis.ru
|
9
9
|
#
|
10
10
|
require 'uri'
|
11
|
-
# initialize the Redis engine for each Iodine process
|
11
|
+
# initialize the Redis engine for each Iodine process.
|
12
12
|
if ENV["REDIS_URL"]
|
13
13
|
uri = URI(ENV["REDIS_URL"])
|
14
14
|
Iodine.default_pubsub = Iodine::PubSub::RedisEngine.new(uri.host, uri.port, 0, uri.password)
|
15
15
|
else
|
16
|
-
puts "* No Redis
|
16
|
+
puts "* No Redis, it's okay, pub/sub will still run on the whole process cluster."
|
17
17
|
end
|
18
|
-
puts "The default Pub/Sub engine is:", Iodine.default_pubsub
|
19
18
|
|
20
19
|
# A simple router - Checks for Websocket Upgrade and answers HTTP.
|
21
20
|
module MyHTTPRouter
|
data/iodine.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ['Boaz Segev']
|
10
10
|
spec.email = ['bo@plezi.io']
|
11
11
|
|
12
|
-
spec.summary = '
|
13
|
-
spec.description = '
|
12
|
+
spec.summary = 'iodine - HTTP / Websocket Server with Pub/Sub support, optimized for Ruby MRI on Linux / BSD'
|
13
|
+
spec.description = 'iodine - HTTP / Websocket Server with Pub/Sub support, optimized for Ruby MRI on Linux / BSD'
|
14
14
|
spec.homepage = 'https://github.com/boazsegev/iodine'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
@@ -32,7 +32,6 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.required_ruby_version = '>= 2.2.2' # Because earlier versions had been discontinued
|
33
33
|
|
34
34
|
spec.add_dependency 'rack'
|
35
|
-
spec.add_dependency 'rake-compiler', '>= 1'
|
36
35
|
|
37
36
|
spec.requirements << 'A Unix based system: Linux / macOS / BSD.'
|
38
37
|
spec.requirements << 'An updated C compiler.'
|
@@ -42,6 +41,7 @@ Gem::Specification.new do |spec|
|
|
42
41
|
spec.add_development_dependency 'bundler', '>= 1.10'
|
43
42
|
spec.add_development_dependency 'rake', '~> 12.0'
|
44
43
|
spec.add_development_dependency 'minitest', '>=5'
|
44
|
+
spec.add_development_dependency 'rake-compiler', '>= 1'
|
45
45
|
|
46
46
|
# spec.post_install_message = "** WARNING!\n" \
|
47
47
|
# "Iodine 0.2.0 is NOT an upgrade - it's a total rewrite, it's written in C specifically for Ruby MRI.\n\n" \
|
data/lib/iodine.rb
CHANGED
@@ -152,16 +152,18 @@ module Iodine
|
|
152
152
|
# Use {warmup} when either {processes} or {threads} are set to more then 1.
|
153
153
|
def self.warmup app
|
154
154
|
# load anything marked with `autoload`, since autoload isn't thread safe nor fork friendly.
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
155
|
+
Iodine.run do
|
156
|
+
Module.constants.each do |n|
|
157
|
+
begin
|
158
|
+
Object.const_get(n)
|
159
|
+
rescue Exception => _e
|
160
|
+
end
|
159
161
|
end
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
162
|
+
::Rack::Builder.new(app) do |r|
|
163
|
+
r.warmup do |a|
|
164
|
+
client = ::Rack::MockRequest.new(a)
|
165
|
+
client.get('/')
|
166
|
+
end
|
165
167
|
end
|
166
168
|
end
|
167
169
|
end
|
data/lib/iodine/monkeypatch.rb
CHANGED
@@ -11,27 +11,32 @@ module Iodine
|
|
11
11
|
#
|
12
12
|
# require 'iodine'
|
13
13
|
# require 'rack'
|
14
|
+
# # a String in need of decoding
|
14
15
|
# s = '%E3%83%AB%E3%83%93%E3%82%A4%E3%82%B9%E3%81%A8'
|
15
16
|
# Benchmark.bm do |bm|
|
16
17
|
# # Pre-Patch
|
17
|
-
# bm.report("Rack") {1_000_000.times { Rack::Utils.unescape s } }
|
18
|
-
#
|
18
|
+
# bm.report(" Rack.unescape") {1_000_000.times { Rack::Utils.unescape s } }
|
19
|
+
# bm.report(" Rack.rfc2822") {1_000_000.times { Rack::Utils.rfc2822(Time.now) } }
|
20
|
+
# bm.report(" Rack.rfc2109") {1_000_000.times { Rack::Utils.rfc2109(Time.now) } }
|
19
21
|
# # Perform Patch
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# define_singleton_method(m,
|
23
|
-
# Iodine::Base::MonkeyPatch::RackUtils.instance_method(m) )
|
24
|
-
# end
|
25
|
-
# end
|
26
|
-
#
|
22
|
+
# Iodine.patch_rack
|
23
|
+
# puts " --- Monkey Patching Rack ---"
|
27
24
|
# # Post Patch
|
28
|
-
# bm.report("Patched")
|
25
|
+
# bm.report("Patched.unescape") {1_000_000.times { Rack::Utils.unescape s } }
|
26
|
+
# bm.report(" Patched.rfc2822") {1_000_000.times { Rack::Utils.rfc2822(Time.now) } }
|
27
|
+
# bm.report(" Patched.rfc2109") {1_000_000.times { Rack::Utils.rfc2109(Time.now) } }
|
29
28
|
# end && nil
|
30
29
|
#
|
31
30
|
# Results:
|
32
31
|
# user system total real
|
33
|
-
#
|
34
|
-
#
|
32
|
+
# Rack.unescape 8.660000 0.010000 8.670000 ( 8.687807)
|
33
|
+
# Rack.rfc2822 3.730000 0.000000 3.730000 ( 3.727732)
|
34
|
+
# Rack.rfc2109 3.020000 0.010000 3.030000 ( 3.031940)
|
35
|
+
# --- Monkey Patching Rack ---
|
36
|
+
# Patched.unescape 0.340000 0.000000 0.340000 ( 0.341506)
|
37
|
+
# Patched.rfc2822 0.740000 0.000000 0.740000 ( 0.737796)
|
38
|
+
# Patched.rfc2109 0.690000 0.010000 0.700000 ( 0.700155)
|
39
|
+
#
|
35
40
|
module RackUtils
|
36
41
|
end
|
37
42
|
end
|
data/lib/iodine/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iodine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Boaz Segev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake-compiler
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '1'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '1'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: bundler
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,8 +66,22 @@ dependencies:
|
|
80
66
|
- - ">="
|
81
67
|
- !ruby/object:Gem::Version
|
82
68
|
version: '5'
|
83
|
-
|
84
|
-
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake-compiler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1'
|
83
|
+
description: iodine - HTTP / Websocket Server with Pub/Sub support, optimized for
|
84
|
+
Ruby MRI on Linux / BSD
|
85
85
|
email:
|
86
86
|
- bo@plezi.io
|
87
87
|
executables:
|
@@ -240,6 +240,6 @@ rubyforge_project:
|
|
240
240
|
rubygems_version: 2.6.11
|
241
241
|
signing_key:
|
242
242
|
specification_version: 4
|
243
|
-
summary:
|
244
|
-
|
243
|
+
summary: iodine - HTTP / Websocket Server with Pub/Sub support, optimized for Ruby
|
244
|
+
MRI on Linux / BSD
|
245
245
|
test_files: []
|