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/CHANGELOG
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
== 0.6.3 Ninja Cookie release
|
2
|
+
* Add Ramaze Rackup config file in example dir [tmm1]
|
3
|
+
Use like this from you Ramaze app dir:
|
4
|
+
|
5
|
+
thin start -r /path/to/thin/example/ramaze.ru
|
6
|
+
|
7
|
+
* Add the --rackup option to load a Rack config file instead of the Rails adapter.
|
8
|
+
So you can use any framework with the thin script and start cluster and stuff like that.
|
9
|
+
A Rack config file is one that is usable through the rackup command and looks like this:
|
10
|
+
|
11
|
+
use Rack::CommonLogger
|
12
|
+
run MyCrazyRackAdapter.new(:uterly, 'cool')
|
13
|
+
|
14
|
+
Then use it with thin like this:
|
15
|
+
|
16
|
+
thin start --rackup config.ru
|
17
|
+
|
18
|
+
* thin config --chrdir ... -C thin/yml do not change current directory anymore, fixes #33.
|
19
|
+
* Add a better sample god config file in example/thin.god that loads all info from config
|
20
|
+
files in /etc/thin [Gump].
|
21
|
+
* Add support for specifying a custom Connector to the server and a more doc about Server
|
22
|
+
configuration.
|
23
|
+
* Add a script to run thin as a system service that can start at startup, closes #31 [Gump]
|
24
|
+
Setup the service like this:
|
25
|
+
|
26
|
+
sudo thin install /etc/thin
|
27
|
+
|
28
|
+
This will install the boot script under /etc/init.d/thin. Then copy your config files to
|
29
|
+
/etc/thin. Works only under Linux.
|
30
|
+
* Set process name to 'thin server (0.0.0.0:3000)' when running as a daemon, closes #32.
|
31
|
+
* Make sure chdir option from config file is used when present.
|
32
|
+
* Raise an error when starting a server as a daemon and pid file already exist, fixes #27.
|
33
|
+
|
1
34
|
== 0.6.2 Rambo release
|
2
35
|
* Server now let current connections finish before stopping, fixes #18
|
3
36
|
* Fix uploading hanging bug when body is moved to a tempfile,
|
@@ -14,7 +47,7 @@
|
|
14
47
|
* Add --only (-o) option to control only one server of a cluster.
|
15
48
|
* Stylize stats page and make the url configurable from the thin script.
|
16
49
|
* Raise error if attempting to use unix sockets on windows.
|
17
|
-
* Add example config files for http://www.tildeslash.com/monit
|
50
|
+
* Add example config files for http://www.tildeslash.com/monit usage.
|
18
51
|
Include the example file using "include /path/to/thin/monit/file" in your monitrc file.
|
19
52
|
The group settings let you do this to manage your clusters:
|
20
53
|
|
data/bin/thin
CHANGED
@@ -1,168 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
2
|
+
# Thin command line interface script.
|
3
3
|
# Run <tt>thin -h</tt> to get more usage.
|
4
4
|
require File.dirname(__FILE__) + '/../lib/thin'
|
5
|
-
require 'optparse'
|
6
|
-
require 'yaml'
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
# Default options values
|
11
|
-
options = {
|
12
|
-
:chdir => Dir.pwd,
|
13
|
-
:environment => 'development',
|
14
|
-
:address => '0.0.0.0',
|
15
|
-
:port => 3000,
|
16
|
-
:timeout => 60,
|
17
|
-
:log => 'log/thin.log',
|
18
|
-
:pid => 'tmp/pids/thin.pid',
|
19
|
-
:servers => 1 # no cluster
|
20
|
-
}
|
21
|
-
|
22
|
-
# NOTE: If you add an option here make sure the key in the +options+ hash is the
|
23
|
-
# same as the name of the command line option.
|
24
|
-
# +option+ keys are use to build the command line to launch a cluster,
|
25
|
-
# see <tt>lib/thin/cluster.rb</tt>.
|
26
|
-
opts = OptionParser.new do |opts|
|
27
|
-
opts.banner = "Usage: thin [options] #{COMMANDS.join('|')}"
|
28
|
-
|
29
|
-
opts.separator ""
|
30
|
-
opts.separator "Server options:"
|
31
|
-
|
32
|
-
opts.on("-a", "--address HOST", "bind to HOST address (default: 0.0.0.0)") { |host| options[:address] = host }
|
33
|
-
opts.on("-p", "--port PORT", "use PORT (default: 3000)") { |port| options[:port] = port.to_i }
|
34
|
-
opts.on("-S", "--socket PATH", "bind to unix domain socket") { |file| options[:socket] = file }
|
35
|
-
opts.on("-e", "--environment ENV", "Rails environment (default: development)") { |env| options[:environment] = env }
|
36
|
-
opts.on("-c", "--chdir PATH", "Change to dir before starting") { |dir| options[:chdir] = File.expand_path(dir) }
|
37
|
-
opts.on("-t", "--timeout SEC", "Request or command timeout in sec",
|
38
|
-
"(default: #{options[:timeout]})") { |sec| options[:timeout] = sec.to_i }
|
39
|
-
opts.on( "--prefix PATH", "Mount the app under PATH (start with /)") { |path| options[:prefix] = path }
|
40
|
-
opts.on( "--stats PATH", "Mount the Stats adapter under PATH") { |path| options[:stats] = path }
|
41
|
-
|
42
|
-
opts.separator ""
|
43
|
-
opts.separator "Daemon options:"
|
44
|
-
|
45
|
-
opts.on("-d", "--daemonize", "Run daemonized in the background") { options[:daemonize] = true }
|
46
|
-
opts.on("-l", "--log FILE", "File to redirect output",
|
47
|
-
"(default: #{options[:log]})") { |file| options[:log] = file }
|
48
|
-
opts.on("-P", "--pid FILE", "File to store PID",
|
49
|
-
"(default: #{options[:pid]})") { |file| options[:pid] = file }
|
50
|
-
opts.on("-u", "--user NAME", "User to run daemon as (use with -g)") { |user| options[:user] = user }
|
51
|
-
opts.on("-g", "--group NAME", "Group to run daemon as (use with -u)") { |group| options[:group] = group }
|
52
|
-
|
53
|
-
opts.separator ""
|
54
|
-
opts.separator "Cluster options:"
|
55
|
-
|
56
|
-
opts.on("-s", "--servers NUM", "Number of servers to start",
|
57
|
-
"set a value >1 to start a cluster") { |num| options[:servers] = num.to_i }
|
58
|
-
opts.on("-o", "--only NUM", "Send command to only one server of the cluster") { |only| options[:only] = only }
|
59
|
-
opts.on("-C", "--config PATH", "Load options from a config file") { |file| options[:config] = file }
|
60
|
-
|
61
|
-
opts.separator ""
|
62
|
-
opts.separator "Common options:"
|
63
|
-
|
64
|
-
opts.on_tail("-D", "--debug", "Set debbuging on") { $DEBUG = true }
|
65
|
-
opts.on_tail("-V", "--trace", "Set tracing on") { $TRACE = true }
|
66
|
-
opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
|
67
|
-
opts.on_tail('-v', '--version', "Show version") { puts Thin::SERVER; exit }
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
# == Utilities
|
72
|
-
|
73
|
-
def cluster?(options)
|
74
|
-
options[:only] || (options[:servers] && options[:servers] > 1)
|
75
|
-
end
|
76
|
-
|
77
|
-
def load_options_from_config_file!(options)
|
78
|
-
if file = options.delete(:config)
|
79
|
-
YAML.load_file(file).each { |key, value| options[key.to_sym] = value }
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
|
84
|
-
# == Commands definitions
|
85
|
-
|
86
|
-
def start(options)
|
87
|
-
load_options_from_config_file! options
|
88
|
-
|
89
|
-
if cluster?(options)
|
90
|
-
Thin::Cluster.new(options).start
|
91
|
-
else
|
92
|
-
if options[:socket]
|
93
|
-
server = Thin::Server.new(options[:socket])
|
94
|
-
else
|
95
|
-
server = Thin::Server.new(options[:address], options[:port])
|
96
|
-
end
|
97
|
-
|
98
|
-
server.pid_file = options[:pid]
|
99
|
-
server.log_file = options[:log]
|
100
|
-
server.timeout = options[:timeout]
|
101
|
-
|
102
|
-
if options[:daemonize]
|
103
|
-
server.daemonize
|
104
|
-
server.change_privilege options[:user], options[:group] if options[:user] && options[:group]
|
105
|
-
end
|
106
|
-
|
107
|
-
server.app = Rack::Adapter::Rails.new(options.merge(:root => options[:chdir]))
|
108
|
-
|
109
|
-
# If a prefix is required, wrap in Rack URL mapper
|
110
|
-
server.app = Rack::URLMap.new(options[:prefix] => server.app) if options[:prefix]
|
111
|
-
|
112
|
-
# If a stats are required, wrap in Stats adapter
|
113
|
-
server.app = Thin::Stats::Adapter.new(server.app, options[:stats]) if options[:stats]
|
114
|
-
|
115
|
-
# Register restart procedure
|
116
|
-
server.on_restart { Thin::Command.run(:start, options) }
|
117
|
-
|
118
|
-
server.start
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def stop(options)
|
123
|
-
load_options_from_config_file! options
|
124
|
-
|
125
|
-
if cluster?(options)
|
126
|
-
Thin::Cluster.new(options).stop
|
127
|
-
else
|
128
|
-
Thin::Server.kill(options[:pid], options[:timeout])
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def restart(options)
|
133
|
-
load_options_from_config_file! options
|
134
|
-
|
135
|
-
if cluster?(options)
|
136
|
-
Thin::Cluster.new(options).restart
|
137
|
-
else
|
138
|
-
Thin::Server.restart(options[:pid])
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def config(options)
|
143
|
-
config_file = options.delete(:config) || abort('config option required')
|
144
|
-
|
145
|
-
# Stringify keys
|
146
|
-
options.keys.each { |o| options[o.to_s] = options.delete(o) }
|
147
|
-
|
148
|
-
File.open(config_file, 'w') { |f| f << options.to_yaml }
|
149
|
-
puts "Wrote configuration to #{config_file}"
|
150
|
-
end
|
151
|
-
|
152
|
-
|
153
|
-
# == Runs the command
|
154
|
-
|
155
|
-
opts.parse! ARGV
|
156
|
-
command = ARGV[0]
|
157
|
-
|
158
|
-
Dir.chdir(options[:chdir])
|
159
|
-
|
160
|
-
if COMMANDS.include?(command)
|
161
|
-
send(command, options)
|
162
|
-
elsif command.nil?
|
163
|
-
puts "Command required"
|
164
|
-
puts opts
|
165
|
-
exit 1
|
166
|
-
else
|
167
|
-
abort "Invalid command : #{command}"
|
168
|
-
end
|
6
|
+
Thin::Runner.new(ARGV).run!
|
data/example/config.ru
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Run with: rackup -s thin
|
2
|
-
#
|
2
|
+
# then browse to http://localhost:9292
|
3
|
+
# Or with: thin start -r config.ru
|
4
|
+
# then browse to http://localhost:3000
|
5
|
+
#
|
3
6
|
# Check Rack::Builder doc for more details on this file format:
|
4
7
|
# http://rack.rubyforge.org/doc/classes/Rack/Builder.html
|
5
8
|
|
data/example/ramaze.ru
ADDED
data/example/thin.god
CHANGED
@@ -1,72 +1,76 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
1
|
+
# == God config file
|
2
|
+
# http://god.rubyforge.org/
|
3
|
+
# Author: Gump
|
4
|
+
#
|
5
|
+
# Config file for god that configures watches for each instance of a thin server for
|
6
|
+
# each thin configuration file found in /etc/thin.
|
7
|
+
# In order to get it working on Ubuntu, I had to make a change to god as noted at
|
8
|
+
# the following blog:
|
9
|
+
# http://blog.alexgirard.com/2007/10/25/ruby-one-line-to-save-god/
|
10
|
+
#
|
11
|
+
require 'yaml'
|
5
12
|
|
6
|
-
|
13
|
+
config_path = "/etc/thin"
|
7
14
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
w.interval = 5.seconds # default
|
12
|
-
w.start = "thin start -c #{RAILS_ROOT} -P #{RAILS_ROOT}/tmp/pids/thin.3000.pid -p 3000 -d"
|
13
|
-
w.stop = "thin stop -P #{RAILS_ROOT}/tmp/pids/thin.3000.pid"
|
14
|
-
w.restart = "thin restart -P #{RAILS_ROOT}/tmp/pids/thin.3000.pid -p 3000"
|
15
|
-
w.pid_file = File.join(RAILS_ROOT, "tmp/pids/thin.3000.pid")
|
16
|
-
|
17
|
-
# clean pid files before start if necessary
|
18
|
-
w.behavior(:clean_pid_file)
|
19
|
-
|
20
|
-
# determine the state on startup
|
21
|
-
w.transition(:init, { true => :up, false => :start }) do |on|
|
22
|
-
on.condition(:process_running) do |c|
|
23
|
-
c.running = true
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# determine when process has finished starting
|
28
|
-
w.transition([:start, :restart], :up) do |on|
|
29
|
-
on.condition(:process_running) do |c|
|
30
|
-
c.running = true
|
31
|
-
end
|
32
|
-
|
33
|
-
# failsafe
|
34
|
-
on.condition(:tries) do |c|
|
35
|
-
c.times = 5
|
36
|
-
c.transition = :start
|
37
|
-
end
|
38
|
-
end
|
15
|
+
Dir[config_path + "/*.yml"].each do |file|
|
16
|
+
config = YAML.load_file(file)
|
17
|
+
num_servers = config["servers"] ||= 1
|
39
18
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
19
|
+
for i in 0...num_servers
|
20
|
+
God.watch do |w|
|
21
|
+
w.group = "thin-" + File.basename(file, ".yml")
|
22
|
+
w.name = w.group + "-#{i}"
|
23
|
+
|
24
|
+
w.interval = 30.seconds
|
25
|
+
|
26
|
+
w.uid = config["user"]
|
27
|
+
w.gid = config["group"]
|
28
|
+
|
29
|
+
w.start = "thin start -C #{file} -o #{i}"
|
30
|
+
w.start_grace = 10.seconds
|
31
|
+
|
32
|
+
w.stop = "thin stop -C #{file} -o #{i}"
|
33
|
+
w.stop_grace = 10.seconds
|
34
|
+
|
35
|
+
w.restart = "thin restart -C #{file} -o #{i}"
|
36
|
+
|
37
|
+
pid_path = config["chdir"] + "/" + config["pid"]
|
38
|
+
ext = File.extname(pid_path)
|
39
|
+
|
40
|
+
w.pid_file = pid_path.gsub(/#{ext}$/, ".#{i}#{ext}")
|
41
|
+
|
42
|
+
w.behavior(:clean_pid_file)
|
43
|
+
|
44
|
+
w.start_if do |start|
|
45
|
+
start.condition(:process_running) do |c|
|
46
|
+
c.interval = 5.seconds
|
47
|
+
c.running = false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
w.restart_if do |restart|
|
52
|
+
restart.condition(:memory_usage) do |c|
|
53
|
+
c.above = 150.megabytes
|
54
|
+
c.times = [3,5] # 3 out of 5 intervals
|
55
|
+
end
|
56
|
+
|
57
|
+
restart.condition(:cpu_usage) do |c|
|
58
|
+
c.above = 50.percent
|
59
|
+
c.times = 5
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
w.lifecycle do |on|
|
64
|
+
on.condition(:flapping) do |c|
|
65
|
+
c.to_state = [:start, :restart]
|
66
|
+
c.times = 5
|
67
|
+
c.within = 5.minutes
|
68
|
+
c.transition = :unmonitored
|
69
|
+
c.retry_in = 10.minutes
|
70
|
+
c.retry_times = 5
|
71
|
+
c.retry_within = 2.hours
|
72
|
+
end
|
73
|
+
end
|
70
74
|
end
|
71
75
|
end
|
72
76
|
end
|
data/lib/rack/adapter/rails.rb
CHANGED
data/lib/rack/handler/thin.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
module Rack
|
2
2
|
module Handler
|
3
|
+
# Rack Handler stricly to be able to use Thin through the rackup command.
|
4
|
+
# To do so, simply require 'thin' in your Rack config file and run like this
|
5
|
+
#
|
6
|
+
# rackup --server thin
|
7
|
+
#
|
3
8
|
class Thin
|
4
9
|
def self.run(app, options={})
|
5
10
|
server = ::Thin::Server.new(options[:Host] || '0.0.0.0',
|
6
11
|
options[:Port] || 8080,
|
7
12
|
app)
|
8
13
|
yield server if block_given?
|
9
|
-
server.start
|
14
|
+
server.start
|
10
15
|
end
|
11
16
|
end
|
12
17
|
end
|
data/lib/thin.rb
CHANGED
@@ -11,10 +11,6 @@ require 'thin/version'
|
|
11
11
|
require 'thin/statuses'
|
12
12
|
|
13
13
|
module Thin
|
14
|
-
NAME = 'thin'.freeze
|
15
|
-
SERVER = "#{NAME} #{VERSION::STRING} codename #{VERSION::CODENAME}".freeze
|
16
|
-
|
17
|
-
autoload :Cluster, 'thin/cluster'
|
18
14
|
autoload :Command, 'thin/command'
|
19
15
|
autoload :Connection, 'thin/connection'
|
20
16
|
autoload :Daemonizable, 'thin/daemonizing'
|
@@ -22,8 +18,21 @@ module Thin
|
|
22
18
|
autoload :Headers, 'thin/headers'
|
23
19
|
autoload :Request, 'thin/request'
|
24
20
|
autoload :Response, 'thin/response'
|
21
|
+
autoload :Runner, 'thin/runner'
|
25
22
|
autoload :Server, 'thin/server'
|
26
23
|
autoload :Stats, 'thin/stats'
|
24
|
+
|
25
|
+
module Connectors
|
26
|
+
autoload :Connector, 'thin/connectors/connector'
|
27
|
+
autoload :TcpServer, 'thin/connectors/tcp_server'
|
28
|
+
autoload :UnixServer, 'thin/connectors/unix_server'
|
29
|
+
end
|
30
|
+
|
31
|
+
module Controllers
|
32
|
+
autoload :Cluster, 'thin/controllers/cluster'
|
33
|
+
autoload :Controller, 'thin/controllers/controller'
|
34
|
+
autoload :Service, 'thin/controllers/service'
|
35
|
+
end
|
27
36
|
end
|
28
37
|
|
29
38
|
require 'rack'
|
data/lib/thin/command.rb
CHANGED
@@ -3,14 +3,15 @@ module Thin
|
|
3
3
|
class Command
|
4
4
|
include Logging
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
class << self
|
7
|
+
# Path to the +thin+ script used to control the servers.
|
8
|
+
# Leave this to default to use the one in the path.
|
9
|
+
attr_accessor :script
|
10
|
+
end
|
9
11
|
|
10
12
|
def initialize(name, options={})
|
11
13
|
@name = name
|
12
14
|
@options = options
|
13
|
-
@script = $PROGRAM_NAME
|
14
15
|
end
|
15
16
|
|
16
17
|
def self.run(*args)
|
@@ -34,7 +35,10 @@ module Thin
|
|
34
35
|
else "--#{name.to_s.tr('_', '-')}=#{value.inspect}"
|
35
36
|
end
|
36
37
|
end
|
37
|
-
|
38
|
+
|
39
|
+
raise ArgumentError, "Path to thin script can't be found, set Command.script" unless self.class.script
|
40
|
+
|
41
|
+
"#{self.class.script} #{@name} #{shellified_options.compact.join(' ')}"
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|