thin 0.6.2-x86-mswin32-60 → 0.6.3-x86-mswin32-60
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 +34 -1
- data/bin/thin +2 -164
- data/example/config.ru +4 -1
- data/example/ramaze.ru +12 -0
- data/example/thin.god +70 -66
- data/lib/rack/adapter/rails.rb +0 -3
- data/lib/rack/handler/thin.rb +6 -1
- data/lib/thin.rb +13 -4
- data/lib/thin/command.rb +9 -5
- data/lib/thin/connection.rb +5 -14
- data/lib/thin/connectors/connector.rb +61 -0
- data/lib/thin/connectors/tcp_server.rb +29 -0
- data/lib/thin/connectors/unix_server.rb +48 -0
- data/lib/thin/controllers/cluster.rb +115 -0
- data/lib/thin/controllers/controller.rb +85 -0
- data/lib/thin/controllers/service.rb +73 -0
- data/lib/thin/controllers/service.sh.erb +39 -0
- data/lib/thin/daemonizing.rb +9 -4
- data/lib/thin/headers.rb +2 -2
- data/lib/thin/runner.rb +166 -0
- data/lib/thin/server.rb +109 -89
- data/lib/thin/stats.html.erb +216 -0
- data/lib/thin/stats.rb +1 -249
- data/lib/thin/version.rb +10 -3
- data/lib/thin_parser.so +0 -0
- data/spec/command_spec.rb +0 -1
- data/spec/configs/cluster.yml +9 -0
- data/spec/configs/single.yml +9 -0
- data/spec/{cluster_spec.rb → controllers/cluster_spec.rb} +22 -10
- data/spec/controllers/controller_spec.rb +85 -0
- data/spec/controllers/service_spec.rb +51 -0
- data/spec/daemonizing_spec.rb +73 -9
- data/spec/request/mongrel_spec.rb +39 -0
- data/spec/{request_spec.rb → request/parser_spec.rb} +11 -143
- data/spec/request/perf_spec.rb +50 -0
- data/spec/request/processing_spec.rb +46 -0
- data/spec/runner_spec.rb +135 -0
- data/spec/server/builder_spec.rb +38 -0
- data/spec/server/stopping_spec.rb +45 -0
- data/spec/server/tcp_spec.rb +54 -0
- data/spec/server/unix_socket_spec.rb +30 -0
- data/spec/spec_helper.rb +49 -16
- data/tasks/announce.rake +7 -3
- data/tasks/email.erb +8 -18
- data/tasks/stats.rake +21 -8
- metadata +33 -7
- data/lib/thin/cluster.rb +0 -123
- data/spec/server_spec.rb +0 -200
data/lib/thin/version.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
module Thin
|
1
|
+
module Thin
|
2
2
|
# Raised when a feature is not supported on the
|
3
3
|
# current platform.
|
4
4
|
class PlatformNotSupported < RuntimeError; end
|
@@ -6,17 +6,24 @@ module Thin
|
|
6
6
|
module VERSION #:nodoc:
|
7
7
|
MAJOR = 0
|
8
8
|
MINOR = 6
|
9
|
-
TINY =
|
9
|
+
TINY = 3
|
10
10
|
|
11
11
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
12
12
|
|
13
|
-
CODENAME = '
|
13
|
+
CODENAME = 'Ninja Cookie'
|
14
14
|
end
|
15
15
|
|
16
|
+
NAME = 'thin'.freeze
|
17
|
+
SERVER = "#{NAME} #{VERSION::STRING} codename #{VERSION::CODENAME}".freeze
|
18
|
+
|
16
19
|
def self.win?
|
17
20
|
RUBY_PLATFORM =~ /mswin/
|
18
21
|
end
|
19
22
|
|
23
|
+
def self.linux?
|
24
|
+
RUBY_PLATFORM =~ /linux/
|
25
|
+
end
|
26
|
+
|
20
27
|
def self.ruby_18?
|
21
28
|
RUBY_VERSION =~ /^1\.8/
|
22
29
|
end
|
data/lib/thin_parser.so
CHANGED
Binary file
|
data/spec/command_spec.rb
CHANGED
@@ -3,7 +3,6 @@ require File.dirname(__FILE__) + '/spec_helper'
|
|
3
3
|
describe Command do
|
4
4
|
before do
|
5
5
|
@command = Command.new(:start, :port => 3000, :daemonize => true, :log => 'hi.log', :pid => nil)
|
6
|
-
@command.script = File.dirname(__FILE__) + '/../bin/thin'
|
7
6
|
@command.silent = true
|
8
7
|
end
|
9
8
|
|
@@ -1,8 +1,9 @@
|
|
1
|
-
require File.dirname(__FILE__) + '
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
include Controllers
|
2
3
|
|
3
4
|
describe Cluster, "with host and port" do
|
4
5
|
before do
|
5
|
-
@cluster = Cluster.new(:chdir =>
|
6
|
+
@cluster = Cluster.new(:chdir => '/rails_app',
|
6
7
|
:address => '0.0.0.0',
|
7
8
|
:port => 3000,
|
8
9
|
:servers => 3,
|
@@ -10,7 +11,6 @@ describe Cluster, "with host and port" do
|
|
10
11
|
:log => 'thin.log',
|
11
12
|
:pid => 'thin.pid'
|
12
13
|
)
|
13
|
-
@cluster.script = File.dirname(__FILE__) + '/../bin/thin'
|
14
14
|
@cluster.silent = true
|
15
15
|
end
|
16
16
|
|
@@ -18,6 +18,10 @@ describe Cluster, "with host and port" do
|
|
18
18
|
@cluster.send(:include_server_number, 'thin.log', 3000).should == 'thin.3000.log'
|
19
19
|
@cluster.send(:include_server_number, 'thin.pid', 3000).should == 'thin.3000.pid'
|
20
20
|
end
|
21
|
+
|
22
|
+
it "should exclude :servers option" do
|
23
|
+
@cluster.options.should_not have_key(:servers)
|
24
|
+
end
|
21
25
|
|
22
26
|
it 'should call each server' do
|
23
27
|
calls = []
|
@@ -45,13 +49,13 @@ describe Cluster, "with host and port" do
|
|
45
49
|
|
46
50
|
private
|
47
51
|
def options_for_port(port)
|
48
|
-
{ :daemonize => true, :log => "thin.#{port}.log", :timeout => 10, :address => "0.0.0.0", :port => port, :pid => "thin.#{port}.pid", :chdir => "
|
52
|
+
{ :daemonize => true, :log => "thin.#{port}.log", :timeout => 10, :address => "0.0.0.0", :port => port, :pid => "thin.#{port}.pid", :chdir => "/rails_app" }
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|
52
56
|
describe Cluster, "with UNIX socket" do
|
53
57
|
before do
|
54
|
-
@cluster = Cluster.new(:chdir =>
|
58
|
+
@cluster = Cluster.new(:chdir => '/rails_app',
|
55
59
|
:socket => '/tmp/thin.sock',
|
56
60
|
:address => '0.0.0.0',
|
57
61
|
:port => 3000,
|
@@ -60,7 +64,6 @@ describe Cluster, "with UNIX socket" do
|
|
60
64
|
:log => 'thin.log',
|
61
65
|
:pid => 'thin.pid'
|
62
66
|
)
|
63
|
-
@cluster.script = File.dirname(__FILE__) + '/../bin/thin'
|
64
67
|
@cluster.silent = true
|
65
68
|
end
|
66
69
|
|
@@ -69,6 +72,11 @@ describe Cluster, "with UNIX socket" do
|
|
69
72
|
@cluster.send(:include_server_number, 'thin', 0).should == 'thin.0'
|
70
73
|
end
|
71
74
|
|
75
|
+
it "should exclude :address and :port options" do
|
76
|
+
@cluster.options.should_not have_key(:address)
|
77
|
+
@cluster.options.should_not have_key(:port)
|
78
|
+
end
|
79
|
+
|
72
80
|
it 'should call each server' do
|
73
81
|
calls = []
|
74
82
|
@cluster.send(:with_each_server) do |n|
|
@@ -96,13 +104,13 @@ describe Cluster, "with UNIX socket" do
|
|
96
104
|
|
97
105
|
private
|
98
106
|
def options_for_socket(number)
|
99
|
-
{ :daemonize => true, :log => "thin.#{number}.log", :timeout => 10, :socket => "/tmp/thin.#{number}.sock", :pid => "thin.#{number}.pid", :chdir => "
|
107
|
+
{ :daemonize => true, :log => "thin.#{number}.log", :timeout => 10, :socket => "/tmp/thin.#{number}.sock", :pid => "thin.#{number}.pid", :chdir => "/rails_app" }
|
100
108
|
end
|
101
109
|
end
|
102
110
|
|
103
111
|
describe Cluster, "controlling only one server" do
|
104
112
|
before do
|
105
|
-
@cluster = Cluster.new(:chdir =>
|
113
|
+
@cluster = Cluster.new(:chdir => '/rails_app',
|
106
114
|
:address => '0.0.0.0',
|
107
115
|
:port => 3000,
|
108
116
|
:servers => 3,
|
@@ -111,10 +119,14 @@ describe Cluster, "controlling only one server" do
|
|
111
119
|
:pid => 'thin.pid',
|
112
120
|
:only => 3001
|
113
121
|
)
|
114
|
-
@cluster.script = File.dirname(__FILE__) + '/../bin/thin'
|
115
122
|
@cluster.silent = true
|
116
123
|
end
|
117
124
|
|
125
|
+
it "should exclude :servers and :only options" do
|
126
|
+
@cluster.options.should_not have_key(:servers)
|
127
|
+
@cluster.options.should_not have_key(:only)
|
128
|
+
end
|
129
|
+
|
118
130
|
it 'should call only specified server' do
|
119
131
|
calls = []
|
120
132
|
@cluster.send(:with_each_server) do |n|
|
@@ -131,6 +143,6 @@ describe Cluster, "controlling only one server" do
|
|
131
143
|
|
132
144
|
private
|
133
145
|
def options_for_port(port)
|
134
|
-
{ :daemonize => true, :log => "thin.#{port}.log", :timeout => 10, :address => "0.0.0.0", :port => port, :pid => "thin.#{port}.pid", :chdir => "
|
146
|
+
{ :daemonize => true, :log => "thin.#{port}.log", :timeout => 10, :address => "0.0.0.0", :port => port, :pid => "thin.#{port}.pid", :chdir => "/rails_app" }
|
135
147
|
end
|
136
148
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
include Controllers
|
4
|
+
|
5
|
+
describe Controller, 'start' do
|
6
|
+
before do
|
7
|
+
@controller = Controller.new(:address => '0.0.0.0', :port => 3000, :pid => 'thin.pid', :log => 'thin.log', :timeout => 60)
|
8
|
+
|
9
|
+
@server = OpenStruct.new
|
10
|
+
@adapter = OpenStruct.new
|
11
|
+
|
12
|
+
Server.should_receive(:new).with('0.0.0.0', 3000).and_return(@server)
|
13
|
+
Rack::Adapter::Rails.stub!(:new).and_return(@adapter)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should configure server" do
|
17
|
+
@controller.start
|
18
|
+
|
19
|
+
@server.app.should == @adapter
|
20
|
+
@server.pid_file.should == 'thin.pid'
|
21
|
+
@server.log_file.should == 'thin.log'
|
22
|
+
@server.timeout.should == 60
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should start as daemon" do
|
26
|
+
@controller.options[:daemonize] = true
|
27
|
+
@controller.options[:user] = true
|
28
|
+
@controller.options[:group] = true
|
29
|
+
|
30
|
+
@server.should_receive(:daemonize)
|
31
|
+
@server.should_receive(:change_privilege)
|
32
|
+
|
33
|
+
@controller.start
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should configure Rails adapter" do
|
37
|
+
Rack::Adapter::Rails.should_receive(:new).with(@controller.options.merge(:root => nil))
|
38
|
+
|
39
|
+
@controller.start
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should mount app under :prefix" do
|
43
|
+
@controller.options[:prefix] = '/app'
|
44
|
+
@controller.start
|
45
|
+
|
46
|
+
@server.app.class.should == Rack::URLMap
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should mount Stats adapter under :stats" do
|
50
|
+
@controller.options[:stats] = '/stats'
|
51
|
+
@controller.start
|
52
|
+
|
53
|
+
@server.app.class.should == Stats::Adapter
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should load app from Rack config" do
|
57
|
+
@controller.options[:rackup] = 'example/config.ru'
|
58
|
+
@controller.start
|
59
|
+
|
60
|
+
@server.app.class.should == Proc
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe Controller do
|
65
|
+
it "should stop" do
|
66
|
+
Server.should_receive(:kill).with('thin.pid', 10)
|
67
|
+
Controller.new(:pid => 'thin.pid', :timeout => 10).stop
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should restart" do
|
71
|
+
Server.should_receive(:restart).with('thin.pid')
|
72
|
+
Controller.new(:pid => 'thin.pid').restart
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should write configuration file" do
|
76
|
+
silence_stream(STDOUT) do
|
77
|
+
Controller.new(:config => 'test.yml', :port => 5000, :address => '127.0.0.1').config
|
78
|
+
end
|
79
|
+
|
80
|
+
File.read('test.yml').should include('port: 5000', 'address: 127.0.0.1')
|
81
|
+
File.read('test.yml').should_not include('config: ')
|
82
|
+
|
83
|
+
File.delete('test.yml')
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
include Controllers
|
3
|
+
|
4
|
+
describe Service do
|
5
|
+
before(:all) do
|
6
|
+
silence_stream(STDERR) do
|
7
|
+
Service::INITD_PATH = 'tmp/sandbox' + Service::INITD_PATH
|
8
|
+
Service::DEFAULT_CONFIG_PATH = 'tmp/sandbox' + Service::DEFAULT_CONFIG_PATH
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
before do
|
13
|
+
Thin.stub!(:linux?).and_return(true)
|
14
|
+
FileUtils.mkdir_p 'tmp/sandbox'
|
15
|
+
|
16
|
+
@service = Service.new(:all => 'spec/configs')
|
17
|
+
@service.silent = true
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should call command for each config file" do
|
21
|
+
Command.should_receive(:run).with(:start, :config => 'spec/configs/cluster.yml', :daemonize => true)
|
22
|
+
Command.should_receive(:run).with(:start, :config => 'spec/configs/single.yml', :daemonize => true)
|
23
|
+
|
24
|
+
@service.start
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should create /etc/init.d/thin file when calling install" do
|
28
|
+
@service.install
|
29
|
+
|
30
|
+
File.exist?(Service::INITD_PATH).should be_true
|
31
|
+
File.read(Service::INITD_PATH).should include('CONFIG_PATH=tmp/sandbox/etc/thin',
|
32
|
+
'SCRIPT_NAME=tmp/sandbox/etc/init.d/thin',
|
33
|
+
'DAEMON=' + Command.script)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should create /etc/thin dir when calling install" do
|
37
|
+
@service.install
|
38
|
+
|
39
|
+
File.directory?(Service::DEFAULT_CONFIG_PATH).should be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should include specified path in /etc/init.d/thin script" do
|
43
|
+
@service.install('tmp/sandbox/usr/thin')
|
44
|
+
|
45
|
+
File.read(Service::INITD_PATH).should include('CONFIG_PATH=tmp/sandbox/usr/thin')
|
46
|
+
end
|
47
|
+
|
48
|
+
after do
|
49
|
+
FileUtils.rm_rf 'tmp/sandbox'
|
50
|
+
end
|
51
|
+
end
|
data/spec/daemonizing_spec.rb
CHANGED
@@ -1,9 +1,28 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
|
+
class TestServer
|
4
|
+
include Logging # Daemonizable should include this?
|
5
|
+
include Daemonizable
|
6
|
+
|
7
|
+
def stop
|
8
|
+
end
|
9
|
+
|
10
|
+
def name
|
11
|
+
'thin'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
3
15
|
describe 'Daemonizing' do
|
4
|
-
|
5
|
-
|
6
|
-
@
|
16
|
+
|
17
|
+
before(:all) do
|
18
|
+
@logfile = File.dirname(__FILE__) + '/../log/daemonizing_test.log'
|
19
|
+
File.delete(@logfile) if File.exist?(@logfile)
|
20
|
+
@child_processes = []
|
21
|
+
end
|
22
|
+
|
23
|
+
before(:each) do
|
24
|
+
@server = TestServer.new
|
25
|
+
@server.log_file = @logfile
|
7
26
|
@server.pid_file = 'test.pid'
|
8
27
|
@pid = nil
|
9
28
|
end
|
@@ -15,6 +34,7 @@ describe 'Daemonizing' do
|
|
15
34
|
|
16
35
|
it 'should create a pid file' do
|
17
36
|
@pid = fork do
|
37
|
+
@child_processes << Process.pid
|
18
38
|
@server.daemonize
|
19
39
|
sleep 1
|
20
40
|
end
|
@@ -29,6 +49,7 @@ describe 'Daemonizing' do
|
|
29
49
|
|
30
50
|
it 'should redirect stdio to a log file' do
|
31
51
|
@pid = fork do
|
52
|
+
@child_processes << Process.pid
|
32
53
|
@server.log_file = 'daemon_test.log'
|
33
54
|
@server.daemonize
|
34
55
|
|
@@ -49,6 +70,7 @@ describe 'Daemonizing' do
|
|
49
70
|
|
50
71
|
it 'should change privilege' do
|
51
72
|
@pid = fork do
|
73
|
+
@child_processes << Process.pid
|
52
74
|
@server.daemonize
|
53
75
|
@server.change_privilege('root', 'admin')
|
54
76
|
end
|
@@ -58,14 +80,15 @@ describe 'Daemonizing' do
|
|
58
80
|
|
59
81
|
it 'should kill process in pid file' do
|
60
82
|
@pid = fork do
|
83
|
+
@child_processes << Process.pid
|
61
84
|
@server.daemonize
|
62
85
|
loop { sleep 1 }
|
63
86
|
end
|
64
87
|
|
65
|
-
|
88
|
+
server_should_start_in_less_then 3
|
66
89
|
|
67
90
|
silence_stream STDOUT do
|
68
|
-
|
91
|
+
TestServer.kill(@server.pid_file, 1)
|
69
92
|
end
|
70
93
|
|
71
94
|
File.exist?(@server.pid_file).should_not be_true
|
@@ -73,25 +96,66 @@ describe 'Daemonizing' do
|
|
73
96
|
|
74
97
|
it 'should send kill signal if timeout' do
|
75
98
|
@pid = fork do
|
99
|
+
@child_processes << Process.pid
|
76
100
|
@server.should_receive(:stop) # pretend we cannot handle the INT signal
|
77
101
|
@server.daemonize
|
78
102
|
sleep 5
|
79
103
|
end
|
80
104
|
|
81
|
-
|
105
|
+
server_should_start_in_less_then 10
|
82
106
|
|
83
107
|
silence_stream STDOUT do
|
84
|
-
|
108
|
+
TestServer.kill(@server.pid_file, 1)
|
85
109
|
end
|
86
110
|
|
87
111
|
File.exist?(@server.pid_file).should be_false
|
88
112
|
Process.running?(@pid).should be_false
|
89
113
|
end
|
90
114
|
|
91
|
-
it "should restart"
|
115
|
+
it "should restart" do
|
116
|
+
@pid = fork do
|
117
|
+
@child_processes << Process.pid
|
118
|
+
@server.on_restart {}
|
119
|
+
@server.daemonize
|
120
|
+
sleep 5
|
121
|
+
end
|
122
|
+
|
123
|
+
server_should_start_in_less_then 10
|
124
|
+
|
125
|
+
silence_stream STDOUT do
|
126
|
+
TestServer.restart(@server.pid_file)
|
127
|
+
end
|
128
|
+
|
129
|
+
proc { sleep 0.1 while File.exist?(@server.pid_file) }.should take_less_then(10)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should exit if pid file already exist" do
|
133
|
+
@pid = fork do
|
134
|
+
@child_processes << Process.pid
|
135
|
+
@server.daemonize
|
136
|
+
sleep 5
|
137
|
+
end
|
138
|
+
server_should_start_in_less_then 10
|
139
|
+
|
140
|
+
proc { @server.daemonize }.should raise_error(PidFileExist)
|
141
|
+
|
142
|
+
File.exist?(@server.pid_file).should be_true
|
143
|
+
end
|
92
144
|
|
93
|
-
after do
|
145
|
+
after(:each) do
|
94
146
|
Process.kill(9, @pid.to_i) if @pid && Process.running?(@pid.to_i)
|
95
147
|
Process.kill(9, @server.pid) if @server.pid && Process.running?(@server.pid)
|
148
|
+
File.delete(@server.pid_file) rescue nil
|
149
|
+
end
|
150
|
+
|
151
|
+
after(:all) do
|
152
|
+
@child_processes.each do |pid|
|
153
|
+
Process.kill(9, pid) rescue nil
|
154
|
+
end
|
96
155
|
end
|
156
|
+
|
157
|
+
private
|
158
|
+
def server_should_start_in_less_then(sec=10)
|
159
|
+
proc { sleep 0.1 until File.exist?(@server.pid_file) }.should take_less_then(10)
|
160
|
+
end
|
97
161
|
end
|