thin 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of thin might be problematic. Click here for more details.
- data/CHANGELOG +15 -0
- data/README +10 -4
- data/benchmark/abc +0 -0
- data/benchmark/runner +0 -0
- data/bin/thin +0 -0
- data/example/thin_solaris_smf.erb +36 -0
- data/example/thin_solaris_smf.readme.txt +150 -0
- data/ext/thin_parser/common.rl +3 -2
- data/ext/thin_parser/parser.c +15 -38
- data/lib/rack/adapter/loader.rb +69 -0
- data/lib/rack/adapter/rails.rb +17 -8
- data/lib/thin.rb +1 -0
- data/lib/thin/backends/base.rb +17 -0
- data/lib/thin/backends/swiftiply_client.rb +3 -2
- data/lib/thin/backends/tcp_server.rb +1 -1
- data/lib/thin/connection.rb +38 -6
- data/lib/thin/controllers/controller.rb +43 -17
- data/lib/thin/logging.rb +1 -1
- data/lib/thin/request.rb +8 -1
- data/lib/thin/runner.rb +29 -7
- data/lib/thin/server.rb +58 -28
- data/lib/thin/version.rb +3 -3
- data/lib/thin_backend.bundle +0 -0
- data/lib/thin_parser.bundle +0 -0
- data/spec/connection_spec.rb +7 -0
- data/spec/controllers/controller_spec.rb +9 -1
- data/spec/rack/loader_spec.rb +29 -0
- data/spec/{rack_rails_spec.rb → rack/rails_adapter_spec.rb} +15 -3
- data/spec/rails_app/public/dispatch.cgi +0 -0
- data/spec/rails_app/public/dispatch.fcgi +0 -0
- data/spec/rails_app/public/dispatch.rb +0 -0
- data/spec/rails_app/script/about +0 -0
- data/spec/rails_app/script/console +0 -0
- data/spec/rails_app/script/destroy +0 -0
- data/spec/rails_app/script/generate +0 -0
- data/spec/rails_app/script/performance/benchmarker +0 -0
- data/spec/rails_app/script/performance/profiler +0 -0
- data/spec/rails_app/script/performance/request +0 -0
- data/spec/rails_app/script/plugin +0 -0
- data/spec/rails_app/script/process/inspector +0 -0
- data/spec/rails_app/script/process/reaper +0 -0
- data/spec/rails_app/script/process/spawner +0 -0
- data/spec/rails_app/script/runner +0 -0
- data/spec/rails_app/script/server +0 -0
- data/spec/request/parser_spec.rb +22 -0
- data/spec/request/processing_spec.rb +9 -10
- data/spec/runner_spec.rb +14 -1
- data/spec/server/builder_spec.rb +3 -2
- data/spec/server/robustness_spec.rb +34 -0
- data/spec/server/swiftiply_spec.rb +1 -1
- data/spec/server/threaded_spec.rb +27 -0
- data/spec/server_spec.rb +69 -0
- data/spec/spec_helper.rb +10 -5
- data/tasks/gem.rake +2 -2
- data/tasks/spec.rake +24 -16
- metadata +13 -5
- data/doc/benchmarks.txt +0 -86
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Server, 'robustness' do
|
4
|
+
before do
|
5
|
+
start_server do |env|
|
6
|
+
body = 'hello!'
|
7
|
+
[200, { 'Content-Type' => 'text/html', 'Content-Length' => body.size.to_s }, body]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should not crash when header too large" do
|
12
|
+
100.times do
|
13
|
+
begin
|
14
|
+
socket = TCPSocket.new(DEFAULT_TEST_ADDRESS, DEFAULT_TEST_PORT)
|
15
|
+
socket.write("GET / HTTP/1.1\r\n")
|
16
|
+
socket.write("Host: localhost\r\n")
|
17
|
+
socket.write("Connection: close\r\n")
|
18
|
+
10000.times do
|
19
|
+
socket.write("X-Foo: #{'x' * 100}\r\n")
|
20
|
+
socket.flush
|
21
|
+
end
|
22
|
+
socket.write("\r\n")
|
23
|
+
socket.read
|
24
|
+
socket.close
|
25
|
+
rescue Errno::EPIPE, Errno::ECONNRESET
|
26
|
+
# Ignore.
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
after do
|
32
|
+
stop_server
|
33
|
+
end
|
34
|
+
end
|
@@ -10,7 +10,7 @@ else
|
|
10
10
|
end
|
11
11
|
wait_for_socket('0.0.0.0', 3333)
|
12
12
|
sleep 2 # HACK ooh boy, I wish I knew how to make those specs more stable...
|
13
|
-
start_server(
|
13
|
+
start_server('0.0.0.0', 5555, :backend => Backends::SwiftiplyClient, :wait_for_socket => false) do |env|
|
14
14
|
body = env.inspect + env['rack.input'].read
|
15
15
|
[200, { 'Content-Type' => 'text/html', 'Content-Length' => body.size.to_s }, body]
|
16
16
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Server, 'with threads' do
|
4
|
+
before do
|
5
|
+
@requests = 0
|
6
|
+
start_server DEFAULT_TEST_ADDRESS, DEFAULT_TEST_PORT, :threaded => true do |env|
|
7
|
+
sleep env['PATH_INFO'].delete('/').to_i
|
8
|
+
@requests += 1
|
9
|
+
[200, { 'Content-Type' => 'text/html', 'Content-Length' => '2' }, 'hi']
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should process request" do
|
14
|
+
get('/').should_not be_empty
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should process requests when blocked" do
|
18
|
+
slow_request = Thread.new { get('/3') }
|
19
|
+
get('/').should_not be_empty
|
20
|
+
@requests.should == 1
|
21
|
+
slow_request.kill
|
22
|
+
end
|
23
|
+
|
24
|
+
after do
|
25
|
+
stop_server
|
26
|
+
end
|
27
|
+
end
|
data/spec/server_spec.rb
CHANGED
@@ -16,4 +16,73 @@ describe Server do
|
|
16
16
|
@server.config
|
17
17
|
@server.maximum_connections.should < 100_000
|
18
18
|
end
|
19
|
+
|
20
|
+
it "should default to non-threaded" do
|
21
|
+
@server.should_not be_threaded
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should set backend to threaded" do
|
25
|
+
@server.threaded = true
|
26
|
+
@server.backend.should be_threaded
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe Server, "initialization" do
|
31
|
+
it "should set host and port" do
|
32
|
+
server = Server.new('192.168.1.1', 8080)
|
33
|
+
|
34
|
+
server.host.should == '192.168.1.1'
|
35
|
+
server.port.should == 8080
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should set socket" do
|
39
|
+
server = Server.new('/tmp/thin.sock')
|
40
|
+
|
41
|
+
server.socket.should == '/tmp/thin.sock'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should set host, port and app" do
|
45
|
+
app = proc {}
|
46
|
+
server = Server.new('192.168.1.1', 8080, app)
|
47
|
+
|
48
|
+
server.host.should_not be_nil
|
49
|
+
server.app.should == app
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should set socket and app" do
|
53
|
+
app = proc {}
|
54
|
+
server = Server.new('/tmp/thin.sock', app)
|
55
|
+
|
56
|
+
server.socket.should_not be_nil
|
57
|
+
server.app.should == app
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should set socket, nil and app" do
|
61
|
+
app = proc {}
|
62
|
+
server = Server.new('/tmp/thin.sock', nil, app)
|
63
|
+
|
64
|
+
server.socket.should_not be_nil
|
65
|
+
server.app.should == app
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should set host, port and backend" do
|
69
|
+
server = Server.new('192.168.1.1', 8080, :backend => Thin::Backends::SwiftiplyClient)
|
70
|
+
|
71
|
+
server.host.should_not be_nil
|
72
|
+
server.backend.should be_kind_of(Thin::Backends::SwiftiplyClient)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should set host, port, app and backend" do
|
76
|
+
app = proc {}
|
77
|
+
server = Server.new('192.168.1.1', 8080, app, :backend => Thin::Backends::SwiftiplyClient)
|
78
|
+
|
79
|
+
server.host.should_not be_nil
|
80
|
+
server.app.should == app
|
81
|
+
server.backend.should be_kind_of(Thin::Backends::SwiftiplyClient)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should not register signals w/ :signals => false" do
|
85
|
+
Server.should_not_receive(:setup_signals)
|
86
|
+
Server.new(:signals => false)
|
87
|
+
end
|
19
88
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -14,7 +14,11 @@ FileUtils.mkdir_p File.dirname(__FILE__) + '/../log'
|
|
14
14
|
Command.script = File.dirname(__FILE__) + '/../bin/thin'
|
15
15
|
Logging.silent = true
|
16
16
|
|
17
|
-
|
17
|
+
unless Object.const_defined?(:SWIFTIPLY_PATH)
|
18
|
+
SWIFTIPLY_PATH = `which swiftiply`.chomp
|
19
|
+
DEFAULT_TEST_ADDRESS = '0.0.0.0'
|
20
|
+
DEFAULT_TEST_PORT = 3333
|
21
|
+
end
|
18
22
|
|
19
23
|
module Matchers
|
20
24
|
class BeFasterThen
|
@@ -138,12 +142,13 @@ module Helpers
|
|
138
142
|
request
|
139
143
|
end
|
140
144
|
|
141
|
-
def start_server(address=
|
142
|
-
@server = Thin::Server.new(address, port, app)
|
145
|
+
def start_server(address=DEFAULT_TEST_ADDRESS, port=DEFAULT_TEST_PORT, options={}, &app)
|
146
|
+
@server = Thin::Server.new(address, port, options, app)
|
147
|
+
@server.threaded = options[:threaded]
|
143
148
|
@server.timeout = 3
|
144
149
|
|
145
150
|
@thread = Thread.new { @server.start }
|
146
|
-
if wait_for_socket
|
151
|
+
if options[:wait_for_socket]
|
147
152
|
wait_for_socket(address, port)
|
148
153
|
else
|
149
154
|
# If we can't ping the address fallback to just wait for the server to run
|
@@ -157,7 +162,7 @@ module Helpers
|
|
157
162
|
raise "Reactor still running, wtf?" if EventMachine.reactor_running?
|
158
163
|
end
|
159
164
|
|
160
|
-
def wait_for_socket(address=
|
165
|
+
def wait_for_socket(address=DEFAULT_TEST_ADDRESS, port=DEFAULT_TEST_PORT, timeout=5)
|
161
166
|
Timeout.timeout(timeout) do
|
162
167
|
loop do
|
163
168
|
begin
|
data/tasks/gem.rake
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'rake/gempackagetask'
|
2
2
|
|
3
|
-
WIN_SUFFIX = ENV['WIN_SUFFIX'] || '
|
3
|
+
WIN_SUFFIX = ENV['WIN_SUFFIX'] || 'i386-mswin32'
|
4
4
|
|
5
5
|
task :clean => :clobber_package
|
6
6
|
|
@@ -21,7 +21,7 @@ spec = Gem::Specification.new do |s|
|
|
21
21
|
|
22
22
|
s.add_dependency 'rack', '>= 0.2.0'
|
23
23
|
if WIN
|
24
|
-
s.add_dependency 'eventmachine', '
|
24
|
+
s.add_dependency 'eventmachine', '= 0.8.1' # TODO replace w/ latest precompiled
|
25
25
|
else
|
26
26
|
s.add_dependency 'daemons', '>= 1.0.9'
|
27
27
|
s.add_dependency 'eventmachine', '>= 0.10.0' # TODO '>= 0.11.0' when it's released
|
data/tasks/spec.rake
CHANGED
@@ -7,26 +7,34 @@ if RUBY_1_9 # RSpec not yet working w/ Ruby 1.9
|
|
7
7
|
else
|
8
8
|
require 'spec/rake/spectask'
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
10
|
+
PERF_SPECS = FileList['spec/perf/*_spec.rb']
|
11
|
+
WIN_SPECS = %w(
|
12
|
+
spec/backends/unix_server_spec.rb
|
13
|
+
spec/controllers/service_spec.rb
|
14
|
+
spec/daemonizing_spec.rb
|
15
|
+
spec/server/unix_socket_spec.rb
|
16
|
+
spec/server/swiftiply_spec.rb
|
17
|
+
)
|
18
|
+
# HACK Event machine causes some problems when running multiple
|
19
|
+
# tests in the same VM so we split the specs in 2 before I find
|
20
|
+
# a better solution...
|
21
|
+
SPECS2 = %w(spec/server/threaded_spec.rb spec/server/tcp_spec.rb)
|
22
|
+
SPECS = FileList['spec/**/*_spec.rb'] - PERF_SPECS - SPECS2
|
23
|
+
|
24
|
+
def spec_task(name, specs)
|
25
|
+
Spec::Rake::SpecTask.new(name) do |t|
|
26
|
+
t.spec_opts = %w(-fs -c)
|
27
|
+
t.spec_files = specs
|
22
28
|
end
|
23
29
|
end
|
24
|
-
|
30
|
+
|
31
|
+
desc "Run all examples"
|
32
|
+
spec_task :spec, SPECS
|
33
|
+
spec_task :spec2, SPECS2
|
34
|
+
task :spec => [:compile, :spec2]
|
25
35
|
|
26
36
|
desc "Run all performance examples"
|
27
|
-
|
28
|
-
t.spec_files = FileList['spec/perf/*_spec.rb']
|
29
|
-
end
|
37
|
+
spec_task 'spec:perf', PERF_SPECS
|
30
38
|
|
31
39
|
task :check_benchmark_unit_gem do
|
32
40
|
begin
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marc-Andre Cournoyer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-04-06 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -57,16 +57,18 @@ files:
|
|
57
57
|
- benchmark/benchmarker.rb
|
58
58
|
- benchmark/runner
|
59
59
|
- bin/thin
|
60
|
-
- doc/benchmarks.txt
|
61
60
|
- example/adapter.rb
|
62
61
|
- example/config.ru
|
63
62
|
- example/monit_sockets
|
64
63
|
- example/monit_unixsock
|
65
64
|
- example/ramaze.ru
|
66
65
|
- example/thin.god
|
66
|
+
- example/thin_solaris_smf.erb
|
67
|
+
- example/thin_solaris_smf.readme.txt
|
67
68
|
- example/vlad.rake
|
68
69
|
- lib/rack
|
69
70
|
- lib/rack/adapter
|
71
|
+
- lib/rack/adapter/loader.rb
|
70
72
|
- lib/rack/adapter/rails.rb
|
71
73
|
- lib/rack/handler
|
72
74
|
- lib/rack/handler/thin.rb
|
@@ -95,6 +97,8 @@ files:
|
|
95
97
|
- lib/thin/statuses.rb
|
96
98
|
- lib/thin/version.rb
|
97
99
|
- lib/thin.rb
|
100
|
+
- lib/thin_backend.bundle
|
101
|
+
- lib/thin_parser.bundle
|
98
102
|
- spec/backends
|
99
103
|
- spec/backends/swiftiply_client_spec.rb
|
100
104
|
- spec/backends/tcp_server_spec.rb
|
@@ -115,7 +119,9 @@ files:
|
|
115
119
|
- spec/perf/request_perf_spec.rb
|
116
120
|
- spec/perf/response_perf_spec.rb
|
117
121
|
- spec/perf/server_perf_spec.rb
|
118
|
-
- spec/
|
122
|
+
- spec/rack
|
123
|
+
- spec/rack/loader_spec.rb
|
124
|
+
- spec/rack/rails_adapter_spec.rb
|
119
125
|
- spec/rails_app
|
120
126
|
- spec/rails_app/app
|
121
127
|
- spec/rails_app/app/controllers
|
@@ -185,10 +191,12 @@ files:
|
|
185
191
|
- spec/server
|
186
192
|
- spec/server/builder_spec.rb
|
187
193
|
- spec/server/pipelining_spec.rb
|
194
|
+
- spec/server/robustness_spec.rb
|
188
195
|
- spec/server/stopping_spec.rb
|
189
196
|
- spec/server/swiftiply.yml
|
190
197
|
- spec/server/swiftiply_spec.rb
|
191
198
|
- spec/server/tcp_spec.rb
|
199
|
+
- spec/server/threaded_spec.rb
|
192
200
|
- spec/server/unix_socket_spec.rb
|
193
201
|
- spec/server_spec.rb
|
194
202
|
- spec/spec_helper.rb
|
@@ -230,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
230
238
|
requirements: []
|
231
239
|
|
232
240
|
rubyforge_project: thin
|
233
|
-
rubygems_version: 1.0
|
241
|
+
rubygems_version: 1.1.0
|
234
242
|
signing_key:
|
235
243
|
specification_version: 2
|
236
244
|
summary: A thin and fast web server
|
data/doc/benchmarks.txt
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
== Process
|
2
|
-
* rackup ...
|
3
|
-
* nice -n20 httperf --port 9292 --num-conns 9000
|
4
|
-
* nice -n20 ab -n5000 localhost:9292/
|
5
|
-
* nice -n20 ab -n5000 -c10 localhost:9292/
|
6
|
-
* nice -n20 ab -n5000 -c100 localhost:9292/
|
7
|
-
|
8
|
-
== More Benchmarks
|
9
|
-
http://www.webficient.com/2007/08/testing-various-configurations-of-rails.html
|
10
|
-
|
11
|
-
=== WEBrick
|
12
|
-
rackup -s webrick
|
13
|
-
|
14
|
-
==== httperf
|
15
|
-
Reply rate [replies/s]: min 303.8 avg 306.8 max 310.4 stddev 2.8 (5 samples)
|
16
|
-
Reply rate [replies/s]: min 235.8 avg 292.2 max 306.4 stddev 27.7 (6 samples)
|
17
|
-
Reply rate [replies/s]: min 304.8 avg 306.9 max 308.8 stddev 1.5 (5 samples)
|
18
|
-
avg: 302.0 10.7
|
19
|
-
|
20
|
-
==== Concurrency Level 1
|
21
|
-
297.37 [#/sec] (mean)
|
22
|
-
|
23
|
-
==== Concurrency Level 10
|
24
|
-
296.65 [#/sec] (mean) Failed requests: 4 (Connect: 2, Length: 2, Exceptions: 0)
|
25
|
-
298.22 [#/sec] (mean) Failed requests: 4 (Connect: 2, Length: 2, Exceptions: 0)
|
26
|
-
|
27
|
-
==== Concurrency Level 100
|
28
|
-
297.16 [#/sec] (mean) Failed requests: 489 (Connect: 245, Length: 244, Exceptions: 0)
|
29
|
-
|
30
|
-
|
31
|
-
=== Mongrel
|
32
|
-
rackup -s mongrel
|
33
|
-
|
34
|
-
==== httperf
|
35
|
-
Reply rate [replies/s]: min 556.4 avg 580.1 max 613.6 stddev 29.9 (3 samples)
|
36
|
-
Reply rate [replies/s]: min 299.0 avg 502.6 max 613.4 stddev 176.5 (3 samples)
|
37
|
-
Reply rate [replies/s]: min 601.0 avg 608.5 max 616.0 stddev 10.7 (2 samples)
|
38
|
-
Reply rate [replies/s]: min 605.2 avg 608.4 max 611.6 stddev 4.5 (2 samples)
|
39
|
-
avg: 574.9 55.4
|
40
|
-
|
41
|
-
==== Concurrency Level 1
|
42
|
-
556.67 [#/sec] (mean)
|
43
|
-
|
44
|
-
==== Concurrency Level 10
|
45
|
-
622.90 [#/sec] (mean)
|
46
|
-
|
47
|
-
==== Concurrency Level 100
|
48
|
-
428.23 [#/sec] (mean)
|
49
|
-
|
50
|
-
=== Evented Mongrel
|
51
|
-
rackup -r "swiftcore/evented_mongrel" -s mongrel
|
52
|
-
|
53
|
-
==== httperf
|
54
|
-
Reply rate [replies/s]: min 452.4 avg 541.0 max 590.0 stddev 76.9 (3 samples)
|
55
|
-
Reply rate [replies/s]: min 573.2 avg 586.0 max 593.0 stddev 11.1 (3 samples)
|
56
|
-
Reply rate [replies/s]: min 546.6 avg 574.8 max 594.6 stddev 25.0 (3 samples)
|
57
|
-
Reply rate [replies/s]: min 593.6 avg 595.2 max 596.4 stddev 1.5 (3 samples)
|
58
|
-
avg: 574.25 28.625
|
59
|
-
|
60
|
-
==== Concurrency Level 1
|
61
|
-
517.97 [#/sec] (mean)
|
62
|
-
|
63
|
-
==== Concurrency Level 10
|
64
|
-
657.89 [#/sec] (mean)
|
65
|
-
|
66
|
-
==== Concurrency Level 100
|
67
|
-
656.17 [#/sec] (mean)
|
68
|
-
|
69
|
-
=== Thin
|
70
|
-
rackup -s thin
|
71
|
-
|
72
|
-
==== httperf
|
73
|
-
Reply rate [replies/s]: min 671.4 avg 681.0 max 690.7 stddev 13.6 (2 samples)
|
74
|
-
Reply rate [replies/s]: min 690.0 avg 695.8 max 701.7 stddev 8.3 (2 samples)
|
75
|
-
Reply rate [replies/s]: min 643.4 avg 669.4 max 695.4 stddev 36.7 (2 samples)
|
76
|
-
Reply rate [replies/s]: min 694.1 avg 695.8 max 697.6 stddev 2.5 (2 samples)
|
77
|
-
avg: 685.5 15.275
|
78
|
-
|
79
|
-
==== Concurrency Level 1
|
80
|
-
719.53 [#/sec] (mean)
|
81
|
-
|
82
|
-
==== Concurrency Level 10
|
83
|
-
782.11 [#/sec] (mean)
|
84
|
-
|
85
|
-
==== Concurrency Level 100
|
86
|
-
776.40 [#/sec] (mean)
|