sinatra-synchrony 0.1.0.beta.2 → 0.1.0.beta.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/Gemfile.lock +3 -6
- data/README.markdown +31 -18
- data/lib/sinatra/synchrony.rb +11 -2
- data/lib/sinatra/synchrony/mock_session.rb +13 -0
- data/lib/sinatra/synchrony/tcpsocket.rb +6 -0
- data/spec/synchrony_spec.rb +3 -2
- metadata +6 -5
- data/lib/rack/test_synchrony.rb +0 -25
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sinatra-synchrony (0.0.
|
5
|
-
async-rack (= 0.5.1)
|
4
|
+
sinatra-synchrony (0.1.0.beta.2)
|
6
5
|
em-http-request (= 0.3.0)
|
7
6
|
em-resolv-replace (= 1.1.1)
|
8
7
|
em-synchrony (= 0.2.0)
|
@@ -18,9 +17,7 @@ GEM
|
|
18
17
|
RubyInline (3.9.0)
|
19
18
|
ZenTest (~> 4.3)
|
20
19
|
ZenTest (4.5.0)
|
21
|
-
addressable (2.2.
|
22
|
-
async-rack (0.5.1)
|
23
|
-
rack (~> 1.1)
|
20
|
+
addressable (2.2.6)
|
24
21
|
diff-lcs (1.1.2)
|
25
22
|
em-http-request (0.3.0)
|
26
23
|
addressable (>= 2.0.0)
|
@@ -55,7 +52,7 @@ GEM
|
|
55
52
|
ruby_parser (>= 2.0.5)
|
56
53
|
sexp_processor (>= 3.0.5)
|
57
54
|
spruz (0.2.6)
|
58
|
-
tilt (1.3)
|
55
|
+
tilt (1.3.2)
|
59
56
|
wrong (0.5.0)
|
60
57
|
ParseTree (~> 3.0)
|
61
58
|
diff-lcs (~> 1.1.2)
|
data/README.markdown
CHANGED
@@ -43,14 +43,31 @@ If you are developing with a classic style app, just require the gem and it will
|
|
43
43
|
'Sinatra::Synchrony is loaded automatically in classic mode, nothing needed'
|
44
44
|
end
|
45
45
|
|
46
|
+
Net::HTTP / TCPSocket
|
47
|
+
---
|
48
|
+
If you're using anything based on TCPSocket (such as Net::HTTP, which is used by many things), you can replace the native Ruby TCPSocket with one that supports EventMachine and allows for concurrency:
|
49
|
+
|
50
|
+
Sinatra::Synchrony.overload_tcpsocket!
|
51
|
+
|
52
|
+
This will allow you to use things like [RestClient](https://github.com/archiloque/rest-client) without any changes:
|
53
|
+
|
54
|
+
RestClient.get 'http://google.com'
|
55
|
+
|
56
|
+
This is not perfect though - the TCPSocket overload doesn't currently support SSL and will throw an exception. This is more for when you have ruby libraries that use Net::HTTP and you want to try something. If you intend to do HTTP requests, I strongly recommend using [Faraday](https://github.com/technoweenie/faraday) instead, which has support for [EM-HTTP-Request](https://github.com/igrigorik/em-http-request).
|
57
|
+
|
58
|
+
Please encourage Ruby library developers to use (or at least support) Faraday instead of Net::HTTP. Aside from the inability to be concurrent natively, it's a pretty weird and crappy interface, which makes it harder to replace it with something better.
|
59
|
+
|
46
60
|
Tests
|
47
61
|
---
|
62
|
+
Add this to the top of your test file:
|
48
63
|
|
49
|
-
|
64
|
+
Sinatra::Synchrony.patch_tests!
|
65
|
+
|
66
|
+
Then just write your tests as usual, and all tests will be run within EventMachine. You must be in the __test__ environment so that Sinatra will not load Rack::FiberPool.
|
50
67
|
|
51
68
|
Benchmarks
|
52
69
|
---
|
53
|
-
|
70
|
+
Despite enabling synchronous programming without callbacks, there is no performance hit to your application! All the performance benefits you expect from Thin/Rainbows and EventMachine are still there:
|
54
71
|
|
55
72
|
class App < Sinatra::Base
|
56
73
|
register Sinatra::Synchrony
|
@@ -59,7 +76,7 @@ It's pretty fast!
|
|
59
76
|
end
|
60
77
|
end
|
61
78
|
|
62
|
-
|
79
|
+
Benchmarked with rackup -s thin:
|
63
80
|
|
64
81
|
$ ab -c 50 -n 2000 http://127.0.0.1:9292/
|
65
82
|
...
|
@@ -76,24 +93,22 @@ run with rackup -s thin:
|
|
76
93
|
|
77
94
|
Let's try a simple blocking IO example to prove it works. 100 hits to google.com:
|
78
95
|
|
96
|
+
require 'sinatra'
|
97
|
+
require 'sinatra/synchrony'
|
79
98
|
require 'rest-client'
|
80
|
-
|
81
|
-
|
82
|
-
register Sinatra::Synchrony
|
83
|
-
get '/' do
|
84
|
-
# Using EventMachine::HttpRequest
|
85
|
-
# EM::Synchrony.sync(EventMachine::HttpRequest.new('http://google.com').get).response
|
99
|
+
require 'faraday'
|
100
|
+
Faraday.default_adapter = :em_synchrony
|
86
101
|
|
87
|
-
|
88
|
-
|
89
|
-
end
|
102
|
+
get '/' do
|
103
|
+
Faraday.get 'http://google.com'
|
90
104
|
end
|
91
105
|
|
106
|
+
|
92
107
|
$ ab -c 100 -n 100 http://127.0.0.1:9292/
|
93
108
|
...
|
94
|
-
Time taken for tests:
|
95
|
-
|
96
|
-
For a perspective, this operation takes __33 seconds__ without this extension.
|
109
|
+
Time taken for tests: 0.256 seconds
|
110
|
+
|
111
|
+
For a perspective, this operation takes __33 seconds__ without this extension.
|
97
112
|
|
98
113
|
Geoloqi
|
99
114
|
---
|
@@ -101,9 +116,7 @@ This gem was designed to help us develop faster games and internal applications
|
|
101
116
|
|
102
117
|
TODO / Thoughts
|
103
118
|
---
|
104
|
-
*
|
105
|
-
* Provide better method for patching Rack::Test that's less fragile to version changes. This is a big priority and I intend to improve this. Pull requests here welcome!
|
106
|
-
* Research way to run tests with Rack::FiberPool enabled.
|
119
|
+
* We are using this in production without any problems, and it's very stable for us. But you should test before deploying anything with it.
|
107
120
|
* There is work underway to make this a Rack middleware, and integrate that middleware with this plugin. That way, many other frameworks can take advantage of this. There is also work exploratory work to provide support for non-EventMachine Reactor pattern implementations with this approach, but it's beyond the scope of this extension.
|
108
121
|
|
109
122
|
Author
|
data/lib/sinatra/synchrony.rb
CHANGED
@@ -4,7 +4,6 @@ require 'eventmachine'
|
|
4
4
|
require 'em-http-request'
|
5
5
|
require 'em-synchrony'
|
6
6
|
require 'em-resolv-replace'
|
7
|
-
require 'net/http'
|
8
7
|
|
9
8
|
module Sinatra
|
10
9
|
module Synchrony
|
@@ -12,6 +11,16 @@ module Sinatra
|
|
12
11
|
builder.use Rack::FiberPool unless test?
|
13
12
|
super
|
14
13
|
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def patch_tests!
|
17
|
+
require 'sinatra/synchrony/mock_session'
|
18
|
+
end
|
19
|
+
|
20
|
+
def overload_tcpsocket!
|
21
|
+
require 'sinatra/synchrony/tcpsocket'
|
22
|
+
end
|
23
|
+
end
|
15
24
|
end
|
16
25
|
register Synchrony
|
17
|
-
end
|
26
|
+
end
|
data/spec/synchrony_spec.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
ENV['RACK_ENV'] = 'test'
|
2
2
|
require File.join(File.join(File.expand_path(File.dirname(__FILE__))), '..', 'lib', 'sinatra', 'synchrony')
|
3
|
-
require
|
3
|
+
require 'rack/test'
|
4
4
|
require 'minitest/autorun'
|
5
5
|
require 'wrong/adapters/minitest'
|
6
|
+
Sinatra::Synchrony.patch_tests!
|
6
7
|
Wrong.config.alias_assert :expect
|
7
8
|
|
8
9
|
def mock_app(base=Sinatra::Base, &block)
|
@@ -40,4 +41,4 @@ describe 'A mock app' do
|
|
40
41
|
expect { last_response.ok? }
|
41
42
|
expect { last_response.headers['Set-Cookie'] }
|
42
43
|
end
|
43
|
-
end
|
44
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinatra-synchrony
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 62196411
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
9
|
- 0
|
10
10
|
- beta
|
11
|
-
-
|
12
|
-
version: 0.1.0.beta.
|
11
|
+
- 4
|
12
|
+
version: 0.1.0.beta.4
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- Kyle Drake
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2011-
|
20
|
+
date: 2011-08-01 00:00:00 Z
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
23
23
|
name: sinatra
|
@@ -168,8 +168,9 @@ extensions: []
|
|
168
168
|
extra_rdoc_files: []
|
169
169
|
|
170
170
|
files:
|
171
|
+
- lib/sinatra/synchrony/mock_session.rb
|
172
|
+
- lib/sinatra/synchrony/tcpsocket.rb
|
171
173
|
- lib/sinatra/synchrony.rb
|
172
|
-
- lib/rack/test_synchrony.rb
|
173
174
|
- spec/synchrony_spec.rb
|
174
175
|
- Gemfile
|
175
176
|
- Gemfile.lock
|
data/lib/rack/test_synchrony.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'rack/test'
|
2
|
-
# Monkeypatch to provide EM within tests.
|
3
|
-
# If you have a better approach, please send a pull request!
|
4
|
-
|
5
|
-
module Rack
|
6
|
-
class MockSession
|
7
|
-
def request(uri, env)
|
8
|
-
env["HTTP_COOKIE"] ||= cookie_jar.for(uri)
|
9
|
-
@last_request = Rack::Request.new(env)
|
10
|
-
EM.synchrony do
|
11
|
-
status, headers, body = @app.call(@last_request.env)
|
12
|
-
@last_response = MockResponse.new(status, headers, body, env["rack.errors"].flush)
|
13
|
-
body.close if body.respond_to?(:close)
|
14
|
-
cookie_jar.merge(last_response.headers["Set-Cookie"], uri)
|
15
|
-
@after_request.each { |hook| hook.call }
|
16
|
-
if @last_response.respond_to?(:finish)
|
17
|
-
@last_response.finish
|
18
|
-
else
|
19
|
-
@last_response
|
20
|
-
end
|
21
|
-
EM.stop
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|