thin 0.5.0 → 0.5.2

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 (67) hide show
  1. data/COPYING +1 -1
  2. data/README +3 -7
  3. data/Rakefile +6 -163
  4. data/bin/thin +87 -48
  5. data/example/thin.god +72 -0
  6. data/ext/thin_parser/thin.c +7 -7
  7. data/lib/rack/adapter/rails.rb +38 -22
  8. data/lib/thin.rb +2 -1
  9. data/lib/thin/cluster.rb +106 -0
  10. data/lib/thin/connection.rb +3 -4
  11. data/lib/thin/daemonizing.rb +4 -24
  12. data/lib/thin/request.rb +6 -5
  13. data/lib/thin/response.rb +1 -3
  14. data/lib/thin/server.rb +9 -6
  15. data/lib/thin/version.rb +6 -4
  16. data/lib/thin_parser.bundle +0 -0
  17. data/spec/cluster_spec.rb +58 -0
  18. data/spec/daemonizing_spec.rb +1 -2
  19. data/spec/rack_rails_spec.rb +73 -0
  20. data/spec/rails_app/app/controllers/application.rb +10 -0
  21. data/spec/rails_app/app/controllers/simple_controller.rb +19 -0
  22. data/spec/rails_app/app/helpers/application_helper.rb +3 -0
  23. data/spec/rails_app/app/views/simple/index.html.erb +15 -0
  24. data/spec/rails_app/config/boot.rb +109 -0
  25. data/spec/rails_app/config/environment.rb +64 -0
  26. data/spec/rails_app/config/environments/development.rb +18 -0
  27. data/spec/rails_app/config/environments/production.rb +19 -0
  28. data/spec/rails_app/config/environments/test.rb +22 -0
  29. data/spec/rails_app/config/initializers/inflections.rb +10 -0
  30. data/spec/rails_app/config/initializers/mime_types.rb +5 -0
  31. data/spec/rails_app/config/routes.rb +35 -0
  32. data/spec/rails_app/public/404.html +30 -0
  33. data/spec/rails_app/public/422.html +30 -0
  34. data/spec/rails_app/public/500.html +30 -0
  35. data/spec/rails_app/public/dispatch.cgi +10 -0
  36. data/spec/rails_app/public/dispatch.fcgi +24 -0
  37. data/spec/rails_app/public/dispatch.rb +10 -0
  38. data/spec/rails_app/public/favicon.ico +0 -0
  39. data/spec/rails_app/public/images/rails.png +0 -0
  40. data/spec/rails_app/public/index.html +277 -0
  41. data/spec/rails_app/public/javascripts/application.js +2 -0
  42. data/spec/rails_app/public/javascripts/controls.js +963 -0
  43. data/spec/rails_app/public/javascripts/dragdrop.js +972 -0
  44. data/spec/rails_app/public/javascripts/effects.js +1120 -0
  45. data/spec/rails_app/public/javascripts/prototype.js +4225 -0
  46. data/spec/rails_app/public/robots.txt +5 -0
  47. data/spec/rails_app/script/about +3 -0
  48. data/spec/rails_app/script/console +3 -0
  49. data/spec/rails_app/script/destroy +3 -0
  50. data/spec/rails_app/script/generate +3 -0
  51. data/spec/rails_app/script/performance/benchmarker +3 -0
  52. data/spec/rails_app/script/performance/profiler +3 -0
  53. data/spec/rails_app/script/performance/request +3 -0
  54. data/spec/rails_app/script/plugin +3 -0
  55. data/spec/rails_app/script/process/inspector +3 -0
  56. data/spec/rails_app/script/process/reaper +3 -0
  57. data/spec/rails_app/script/process/spawner +3 -0
  58. data/spec/rails_app/script/runner +3 -0
  59. data/spec/rails_app/script/server +3 -0
  60. data/spec/response_spec.rb +16 -0
  61. data/spec/spec_helper.rb +1 -0
  62. metadata +71 -11
  63. data/doc/rdoc/created.rid +0 -1
  64. data/doc/rdoc/files/README.html +0 -197
  65. data/doc/rdoc/index.html +0 -10
  66. data/doc/rdoc/logo.gif +0 -0
  67. data/doc/rdoc/rdoc-style.css +0 -91
data/COPYING CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007 Marc-Andre Cournoyer
1
+ Copyright (c) 2008 Marc-Andre Cournoyer
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
data/README CHANGED
@@ -19,13 +19,9 @@ or using my mirror (might be more recent):
19
19
 
20
20
  Or from source:
21
21
 
22
- git clone http://code.macournoyer.com/git/thin.git
22
+ git clone git://repo.or.cz/thin.git
23
23
  cd thin
24
24
  rake install
25
-
26
- Or from the Subversion mirror (might be out of date):
27
-
28
- svn co http://code.macournoyer.com/svn/thin/trunk thin
29
25
 
30
26
  === Usage
31
27
  A +thin+ script is offered to easily start your Rails application:
@@ -60,5 +56,5 @@ either the terms of the GPL.
60
56
 
61
57
  Thin is copyright Marc-Andre Cournoyer <macournoyer@gmail.com>
62
58
 
63
- Please report any bug at http://code.macournoyer.com/thin/trac.fcgi/newticket
64
- and security issues directly to me at macournoyer@gmail.com.
59
+ Please report any bug at http://groups.google.com/group/thin-ruby/
60
+ and major security issues directly to me at macournoyer@gmail.com.
data/Rakefile CHANGED
@@ -1,174 +1,17 @@
1
+ RUBY_1_9 = RUBY_VERSION =~ /^1\.9/
2
+
1
3
  require 'rake'
2
4
  require 'rake/clean'
3
- require 'rake/rdoctask'
4
- require 'rake/gempackagetask'
5
- require 'spec/rake/spectask'
6
-
7
- require File.dirname(__FILE__) + '/lib/thin'
5
+ require 'lib/thin'
6
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
8
7
 
9
- EXT_DIR = 'ext/thin_parser'
10
- EXT_BUNDLE = "#{EXT_DIR}/thin_parser.#{Config::CONFIG['DLEXT']}"
11
- EXT_FILES = FileList[
12
- "#{EXT_DIR}/*.c",
13
- "#{EXT_DIR}/*.h",
14
- "#{EXT_DIR}/*.rl",
15
- "#{EXT_DIR}/extconf.rb",
16
- "#{EXT_DIR}/Makefile",
17
- "lib"
18
- ]
19
- CLEAN.include %w(doc/rdoc pkg coverage tmp log *.gem **/*.{o,bundle,jar,so,obj,pdb,lib,def,exp,log} ext/*/Makefile ext/*/conftest.dSYM)
20
-
21
- desc "Run all examples"
22
- Spec::Rake::SpecTask.new('spec') do |t|
23
- t.spec_files = FileList['spec/**/*.rb']
24
- end
25
8
  task :default => [:compile, :spec]
26
9
 
27
- Rake::RDocTask.new do |rdoc|
28
- rdoc.rdoc_dir = 'doc/rdoc'
29
- rdoc.options += ['--quiet', '--title', Thin::NAME,
30
- "--opname", "index.html",
31
- "--line-numbers",
32
- "--main", "README",
33
- "--inline-source"]
34
- rdoc.template = "site/rdoc.rb"
35
- rdoc.main = "README"
36
- rdoc.title = Thin::NAME
37
- rdoc.rdoc_files.add %w(README lib/thin/*.rb')
38
- end
39
-
40
- namespace :rdoc do
41
- desc 'Upload rdoc to code.macournoyer.com'
42
- task :upload => :rdoc do
43
- upload "doc/rdoc", 'thin/doc', :replace => true
44
- end
45
- end
46
-
47
- spec = Gem::Specification.new do |s|
48
- s.name = Thin::NAME
49
- s.version = Thin::VERSION::STRING
50
- s.platform = Gem::Platform::RUBY
51
- s.summary =
52
- s.description = "A thin and fast web server"
53
- s.author = "Marc-Andre Cournoyer"
54
- s.email = 'macournoyer@gmail.com'
55
- s.homepage = 'http://code.macournoyer.com/thin/'
56
- s.executables = %w(thin)
57
-
58
- s.required_ruby_version = '>= 1.8.6'
59
-
60
- s.add_dependency 'eventmachine', '>= 0.9.0'
61
- s.add_dependency 'rack', '>= 0.2.0'
62
-
63
- s.files = %w(COPYING README Rakefile) +
64
- Dir.glob("{bin,doc,spec,lib,example}/**/*") +
65
- Dir.glob("ext/**/*.{h,c,rb,rl}") +
66
- s.extensions = FileList["ext/**/extconf.rb"].to_a
67
-
68
- s.require_path = "lib"
69
- s.bindir = "bin"
70
- end
71
-
72
- Rake::GemPackageTask.new(spec) do |p|
73
- p.gem_spec = spec
74
- end
75
-
76
- namespace :gem do
77
- desc 'Upload gem to code.macournoyer.com'
78
- task :upload => :gem do
79
- upload "pkg/#{spec.full_name}.gem", 'gems'
80
- sh 'ssh macournoyer@macournoyer.com "cd code.macournoyer.com && index_gem_repository.rb"'
81
- end
82
-
83
- desc 'Upload gem to rubyforge.org'
84
- task :upload_rubyforge => :gem do
85
- sh 'rubyforge login'
86
- sh "rubyforge add_release thin thin #{Thin::VERSION::STRING} pkg/thin-#{Thin::VERSION::STRING}.gem"
87
- sh "rubyforge add_file thin thin #{Thin::VERSION::STRING} pkg/thin-#{Thin::VERSION::STRING}.gem"
88
- end
89
- end
90
-
91
- task :ragel do
92
- Dir.chdir EXT_DIR do
93
- target = "parser.c"
94
- File.unlink target if File.exist? target
95
- sh "ragel parser.rl | rlgen-cd -G2 -o #{target}"
96
- raise "Failed to compile Ragel state machine" unless File.exist? target
97
- end
98
- end
99
-
100
- desc "Compile the extensions"
101
- task :compile => ["#{EXT_DIR}/Makefile", EXT_BUNDLE]
102
-
103
- task :package => :compile
104
-
105
- file "#{EXT_DIR}/Makefile" => ["#{EXT_DIR}/extconf.rb"] do
106
- cd(EXT_DIR) { ruby "extconf.rb" }
107
- end
108
-
109
- file EXT_BUNDLE => EXT_FILES do
110
- cd EXT_DIR do
111
- sh(PLATFORM =~ /win32/ ? 'nmake' : 'make')
112
- end
113
- cp EXT_BUNDLE, 'lib/'
114
- end
115
-
116
- desc 'Show some stats about the code'
117
- task :stats do
118
- line_count = proc do |path|
119
- Dir[path].collect { |f| File.open(f).readlines.reject { |l| l =~ /(^\s*(\#|\/\*))|^\s*$/ }.size }.inject(0){ |sum,n| sum += n }
120
- end
121
- lib = line_count['lib/**/*.rb']
122
- ext = line_count['ext/**/*.{c,h}']
123
- test = line_count['test/**/*.rb']
124
- ratio = '%1.2f' % (test.to_f / lib.to_f)
125
-
126
- puts "#{lib.to_s.rjust(6)} LOC of lib"
127
- puts "#{ext.to_s.rjust(6)} LOC of ext"
128
- puts "#{test.to_s.rjust(6)} LOC of test"
129
- puts "#{ratio.to_s.rjust(6)} ratio lib/test"
130
- end
131
-
132
- namespace :site do
133
- task :build do
134
- mkdir_p 'tmp/site/images'
135
- cd 'tmp/site' do
136
- ruby '../../site/thin.rb', '--dump'
137
- end
138
- cp 'site/style.css', 'tmp/site'
139
- cp_r Dir['site/images/*'], 'tmp/site/images'
140
- end
141
-
142
- desc 'Upload website to code.macournoyer.com'
143
- task :upload => 'site:build' do
144
- upload 'tmp/site/*', 'thin'
145
- end
146
- end
147
-
148
- namespace :deploy do
149
- task :site => %w(site:upload rdoc:upload)
150
-
151
- desc 'Deploy on code.macournoyer.com'
152
- task :alpha => %w(gem:upload deploy:site)
153
-
154
- desc 'Deploy on rubyforge'
155
- task :public => %w(gem:upload_rubyforge deploy:site)
156
- end
157
- desc 'Deploy on all servers'
158
- task :deploy => %w(deploy:alpha deploy:public)
159
-
160
10
  task :install => :compile do
161
11
  sh %{rake package}
162
- sh %{sudo gem install pkg/#{Thin::NAME}-#{Thin::VERSION::STRING}}
12
+ sh %{sudo #{gem} install pkg/#{Thin::NAME}-#{Thin::VERSION::STRING}}
163
13
  end
164
14
 
165
15
  task :uninstall => :clean do
166
- sh %{sudo gem uninstall #{Thin::NAME}}
16
+ sh %{sudo #{gem} uninstall #{Thin::NAME}}
167
17
  end
168
-
169
- # == Utilities
170
-
171
- def upload(file, to, options={})
172
- sh %{ssh macournoyer@macournoyer.com "rm -rf code.macournoyer.com/#{to}"} if options[:replace]
173
- sh %{scp -rq #{file} macournoyer@macournoyer.com:code.macournoyer.com/#{to}}
174
- end
data/bin/thin CHANGED
@@ -1,79 +1,118 @@
1
1
  #!/usr/bin/env ruby
2
+ # <tt>thin start</tt>: Starts the Rails app in the current directory.
3
+ # Run <tt>thin -h</tt> to get more usage.
2
4
  require File.dirname(__FILE__) + '/../lib/thin'
3
5
  require 'optparse'
4
6
 
7
+ COMMANDS = %w(start stop restart)
8
+
9
+ # Default options values
5
10
  options = {
6
- :root => Dir.pwd,
7
- :env => 'development',
8
- :host => '0.0.0.0',
9
- :port => 3000,
10
- :timeout => 60,
11
- :log_file => 'log/thin.log',
12
- :pid_file => 'tmp/pids/thin.pid'
11
+ :chdir => Dir.pwd,
12
+ :environment => 'development',
13
+ :address => '0.0.0.0',
14
+ :port => 3000,
15
+ :timeout => 60,
16
+ :log => 'log/thin.log',
17
+ :pid => 'tmp/pids/thin.pid',
18
+ :servers => 1 # no cluster
13
19
  }
14
20
 
21
+ # NOTE: If you add an option here make sure the key in the +options+ hash is the
22
+ # same as the name of the command line option.
23
+ # +option+ keys are use to build the command line to launch a cluster,
24
+ # see <tt>lib/thin/cluster.rb</tt>.
15
25
  opts = OptionParser.new do |opts|
16
- opts.banner = "Usage: thin [options] start|stop"
26
+ opts.banner = "Usage: thin [options] #{COMMANDS.join('|')}"
17
27
 
18
28
  opts.separator ""
19
29
  opts.separator "Server options:"
20
30
 
21
- opts.on("-o", "--host HOST", "listen on HOST (default: 0.0.0.0)") { |host| options[:host] = host }
22
- opts.on("-p", "--port PORT", "use PORT (default: 3000)") { |port| options[:port] = port }
23
- opts.on("-e", "--env ENV", "Rails environment (default: development)") { |env| options[:env] = env }
24
- opts.on("-c", "--chdir PATH", "listen on HOST (default: current dir)") { |dir| options[:root] = dir }
25
- opts.on("-d", "--daemonize", "Daemonize") { options[:daemonize] = true }
26
- opts.on("-l", "--log-file FILE", "File to redirect output",
27
- "(default: #{options[:log_file]})") { |file| options[:log_file] = file }
28
- opts.on("-P", "--pid-file FILE", "File to store PID",
29
- "(default: #{options[:pid_file]})") { |file| options[:pid_file] = file }
30
- opts.on("-t", "--timeout SEC", "Request or command timeout in sec",
31
- "(default: #{options[:timeout]})") { |sec| options[:timeout] = sec }
32
- opts.on("-u", "--user NAME", "User to run daemon as (use with -g)") { |user| options[:user] = user }
33
- opts.on("-g", "--group NAME", "Group to run daemon as (use with -u)") { |group| options[:group] = group }
31
+ opts.on("-a", "--address HOST", "bind to HOST address (default: 0.0.0.0)") { |host| options[:address] = host }
32
+ opts.on("-p", "--port PORT", "use PORT (default: 3000)") { |port| options[:port] = port.to_i }
33
+ opts.on("-e", "--environment ENV", "Rails environment (default: development)") { |env| options[:environment] = env }
34
+ opts.on("-c", "--chdir PATH", "Change to dir before starting") { |dir| options[:chdir] = File.expand_path(dir) }
35
+ opts.on("-s", "--servers NUM", "Number of servers to start",
36
+ "set a value >1 to start a cluster") { |num| options[:servers] = num.to_i }
37
+ opts.on("-d", "--daemonize", "Run daemonized in the background") { options[:daemonize] = true }
38
+ opts.on("-l", "--log FILE", "File to redirect output",
39
+ "(default: #{options[:log]})") { |file| options[:log] = file }
40
+ opts.on("-P", "--pid FILE", "File to store PID",
41
+ "(default: #{options[:pid]})") { |file| options[:pid] = file }
42
+ opts.on("-t", "--timeout SEC", "Request or command timeout in sec",
43
+ "(default: #{options[:timeout]})") { |sec| options[:timeout] = sec.to_i }
44
+ opts.on("-u", "--user NAME", "User to run daemon as (use with -g)") { |user| options[:user] = user }
45
+ opts.on("-g", "--group NAME", "Group to run daemon as (use with -u)") { |group| options[:group] = group }
34
46
 
35
47
  opts.separator ""
36
48
  opts.separator "Common options:"
37
49
 
38
- opts.on_tail("-h", "--help", "Show this message") do
39
- puts opts
40
- exit
41
- end
42
-
43
- opts.on_tail('-v', '--version', "Show version") do
44
- puts Thin::NAME
45
- exit
46
- end
50
+ opts.on_tail("-D", "--debug", "Set debbuging on") { $DEBUG = true }
51
+ opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
52
+ opts.on_tail('-v', '--version', "Show version") { puts Thin::SERVER; exit }
47
53
 
48
54
  opts.parse! ARGV
49
55
  end
50
56
 
51
- case ARGV[0]
57
+
58
+ # == Commands definitions
59
+
60
+ def cluster?(options)
61
+ options[:servers] && options[:servers] > 1
62
+ end
63
+
64
+ def start(options)
65
+ if cluster?(options)
66
+ Thin::Cluster.new(options).start
67
+ else
68
+ server = Thin::Server.new(options[:address], options[:port])
69
+
70
+ server.pid_file = options[:pid]
71
+ server.log_file = options[:log]
72
+ server.timeout = options[:timeout]
52
73
 
53
- when 'start'
54
- app = Rack::Adapter::Rails.new(options)
55
- server = Thin::Server.new(options[:host], options[:port], app)
74
+ if options[:daemonize]
75
+ server.change_privilege options[:user], options[:group] if options[:user] && options[:group]
76
+ server.daemonize
77
+ end
56
78
 
57
- server.pid_file = options[:pid_file]
58
- server.log_file = options[:log_file]
59
- server.timeout = options[:timeout]
79
+ server.app = Rack::Adapter::Rails.new(options.merge(:root => options[:chdir]))
80
+ server.start!
81
+ end
82
+ end
83
+
84
+ def stop(options)
85
+ if cluster?(options)
86
+ Thin::Cluster.new(options).stop
87
+ else
88
+ Thin::Server.kill options[:pid], options[:timeout]
89
+ end
90
+ end
91
+
92
+ def restart(options)
93
+ if cluster?(options)
94
+ Thin::Cluster.new(options).restart
95
+ else
96
+ # Restart only make sense when running as a daemon
97
+ options.update :daemonize => true
60
98
 
61
- if options[:daemonize]
62
- server.change_privilege options[:user], options[:group] if options[:user] && options[:group]
63
- server.daemonize
99
+ stop(options)
100
+ start(options)
64
101
  end
102
+ end
103
+
65
104
 
66
- server.start!
105
+ # == Runs the command
67
106
 
68
- when 'stop'
69
- Thin::Server.kill options[:pid_file], options[:timeout]
107
+ Dir.chdir(options[:chdir])
108
+ command = ARGV[0]
70
109
 
71
- when nil
110
+ if COMMANDS.include?(command)
111
+ send(command, options)
112
+ elsif command.nil?
72
113
  puts "Command required"
73
114
  puts opts
74
- exit 1
75
-
115
+ exit 1
76
116
  else
77
- abort "Invalid command : #{ARGV[0]}"
78
-
117
+ abort "Invalid command : #{command}"
79
118
  end
@@ -0,0 +1,72 @@
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
5
+
6
+ RAILS_ROOT = "/Users/marc/projects/refactormycode"
7
+
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
39
+
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
70
+ end
71
+ end
72
+ end