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.

Files changed (48) hide show
  1. data/CHANGELOG +34 -1
  2. data/bin/thin +2 -164
  3. data/example/config.ru +4 -1
  4. data/example/ramaze.ru +12 -0
  5. data/example/thin.god +70 -66
  6. data/lib/rack/adapter/rails.rb +0 -3
  7. data/lib/rack/handler/thin.rb +6 -1
  8. data/lib/thin.rb +13 -4
  9. data/lib/thin/command.rb +9 -5
  10. data/lib/thin/connection.rb +5 -14
  11. data/lib/thin/connectors/connector.rb +61 -0
  12. data/lib/thin/connectors/tcp_server.rb +29 -0
  13. data/lib/thin/connectors/unix_server.rb +48 -0
  14. data/lib/thin/controllers/cluster.rb +115 -0
  15. data/lib/thin/controllers/controller.rb +85 -0
  16. data/lib/thin/controllers/service.rb +73 -0
  17. data/lib/thin/controllers/service.sh.erb +39 -0
  18. data/lib/thin/daemonizing.rb +9 -4
  19. data/lib/thin/headers.rb +2 -2
  20. data/lib/thin/runner.rb +166 -0
  21. data/lib/thin/server.rb +109 -89
  22. data/lib/thin/stats.html.erb +216 -0
  23. data/lib/thin/stats.rb +1 -249
  24. data/lib/thin/version.rb +10 -3
  25. data/lib/thin_parser.so +0 -0
  26. data/spec/command_spec.rb +0 -1
  27. data/spec/configs/cluster.yml +9 -0
  28. data/spec/configs/single.yml +9 -0
  29. data/spec/{cluster_spec.rb → controllers/cluster_spec.rb} +22 -10
  30. data/spec/controllers/controller_spec.rb +85 -0
  31. data/spec/controllers/service_spec.rb +51 -0
  32. data/spec/daemonizing_spec.rb +73 -9
  33. data/spec/request/mongrel_spec.rb +39 -0
  34. data/spec/{request_spec.rb → request/parser_spec.rb} +11 -143
  35. data/spec/request/perf_spec.rb +50 -0
  36. data/spec/request/processing_spec.rb +46 -0
  37. data/spec/runner_spec.rb +135 -0
  38. data/spec/server/builder_spec.rb +38 -0
  39. data/spec/server/stopping_spec.rb +45 -0
  40. data/spec/server/tcp_spec.rb +54 -0
  41. data/spec/server/unix_socket_spec.rb +30 -0
  42. data/spec/spec_helper.rb +49 -16
  43. data/tasks/announce.rake +7 -3
  44. data/tasks/email.erb +8 -18
  45. data/tasks/stats.rake +21 -8
  46. metadata +33 -7
  47. data/lib/thin/cluster.rb +0 -123
  48. 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 useage.
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
- # <tt>thin start</tt>: Starts the Rails app in the current directory.
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
- COMMANDS = %w(start stop restart config)
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!
@@ -1,5 +1,8 @@
1
1
  # Run with: rackup -s thin
2
- # Then browse to http://localhost:9292
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
 
@@ -0,0 +1,12 @@
1
+ # Ramaze Rackup config file.
2
+ # by tmm1
3
+ # Use with --rackup option:
4
+ #
5
+ # thin start -r ramaze.ru
6
+ #
7
+ require 'start'
8
+
9
+ Ramaze.trait[:essentials].delete Ramaze::Adapter
10
+ Ramaze.start :force => true
11
+
12
+ run Ramaze::Adapter::Base
@@ -1,72 +1,76 @@
1
- # WARNING: this config file has not been tested yet.
2
- # If you know God better then I, feel free to tweak it and send it to me.
3
- # Thanks!
4
- # -- Marc
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
- RAILS_ROOT = "/Users/marc/projects/refactormycode"
13
+ config_path = "/etc/thin"
7
14
 
8
- God.watch do |w|
9
- w.name = "thin-3000"
10
- w.group = 'thins'
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
- # start if process is not running
41
- w.transition(:up, :start) do |on|
42
- on.condition(:process_exits)
43
- end
44
-
45
- # restart if memory or cpu is too high
46
- w.transition(:up, :restart) do |on|
47
- on.condition(:memory_usage) do |c|
48
- c.interval = 20
49
- c.above = 50.megabytes
50
- c.times = [3, 5]
51
- end
52
-
53
- on.condition(:cpu_usage) do |c|
54
- c.interval = 10
55
- c.above = 10.percent
56
- c.times = [3, 5]
57
- end
58
- end
59
-
60
- # lifecycle
61
- w.lifecycle do |on|
62
- on.condition(:flapping) do |c|
63
- c.to_state = [:start, :restart]
64
- c.times = 5
65
- c.within = 5.minute
66
- c.transition = :unmonitored
67
- c.retry_in = 10.minutes
68
- c.retry_times = 5
69
- c.retry_within = 2.hours
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
@@ -1,6 +1,3 @@
1
- # This as been submitted to Rack as a patch, tested and everything.
2
- # Bug Christian Neukirchen at chneukirchen@gmail.com to apply the patch!
3
-
4
1
  require 'cgi'
5
2
 
6
3
  # Adapter to run a Rails app with any supported Rack handler.
@@ -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
@@ -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'
@@ -3,14 +3,15 @@ module Thin
3
3
  class Command
4
4
  include Logging
5
5
 
6
- # Path to the +thin+ script used to control the servers.
7
- # Leave this to default to use the one in the path.
8
- attr_accessor :script
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
- "#{@script} #{@name} #{shellified_options.compact.join(' ')}"
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