unicorn 0.96.1 → 0.97.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ *.o
1
2
  *.bundle
2
3
  *.log
3
4
  *.so
@@ -4,7 +4,7 @@
4
4
 
5
5
  # NAME
6
6
 
7
- unicorn_rails - a rackup-like command to launch the Unicorn HTTP server
7
+ unicorn_rails - a script/server-like command to launch the Unicorn HTTP server
8
8
 
9
9
  # SYNOPSIS
10
10
 
@@ -16,6 +16,11 @@ A rackup(1)-like command to launch Rails applications using Unicorn. It
16
16
  is expected to be started in your Rails application root (RAILS_ROOT),
17
17
  but the "working_directory" directive may be used in the CONFIG_FILE.
18
18
 
19
+ It is designed to help Rails 1.x and 2.y users transition to Rack, but
20
+ it is NOT needed for Rails 3 applications. Rails 3 users are encouraged
21
+ to use unicorn(1) instead of unicorn_rails(1). Users of Rails 1.x/2.y
22
+ may also use unicorn(1) instead of unicorn_rails(1).
23
+
19
24
  The outward interface resembles rackup(1), the internals and default
20
25
  middleware loading is designed like the `script/server` command
21
26
  distributed with Rails.
data/FAQ CHANGED
@@ -1,5 +1,12 @@
1
1
  = Frequently Asked Questions about Unicorn
2
2
 
3
+ === I've installed Rack 1.1.x, why can't Unicorn load Rails?
4
+
5
+ Rails 2.3.5 is not compatible with Rack 1.1.x. Unicorn is compatible
6
+ with both Rack 1.1.x and Rack 1.0.x, and RubyGems will load the latest
7
+ version of Rack installed on the system. Uninstalling the Rack 1.1.x
8
+ gem should solve gem loading issues with Rails 2.3.x.
9
+
3
10
  === Why are my redirects going to "http" URLs when my site uses https?
4
11
 
5
12
  If your site is entirely behind https, then Rack applications that use
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.96.1.GIT
4
+ DEF_VER=v0.97.0.GIT
5
5
 
6
6
  LF='
7
7
  '
@@ -1,17 +1,13 @@
1
1
  # use GNU Make to run tests in parallel, and without depending on RubyGems
2
2
  all:: test
3
3
 
4
- ruby = ruby
5
- rake = rake
6
- ragel = ragel
7
-
8
4
  GIT_URL = git://git.bogomips.org/unicorn.git
9
5
  RLFLAGS = -G2
10
6
 
11
7
  # lower-case vars are deprecated
12
- RUBY = $(ruby)
13
- RAKE = $(rake)
14
- RAGEL = $(ragel)
8
+ RUBY = ruby
9
+ RAKE = rake
10
+ RAGEL = ragel
15
11
 
16
12
  GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
17
13
  @./GIT-VERSION-GEN
@@ -62,6 +58,7 @@ lib/unicorn_http.$(DLEXT): $(ext)/unicorn_http.$(DLEXT)
62
58
  install -m644 $< $@
63
59
  http: lib/unicorn_http.$(DLEXT)
64
60
 
61
+ test-install: $(test_prefix)/.stamp
65
62
  $(test_prefix)/.stamp: $(inst_deps)
66
63
  mkdir -p $(test_prefix)/.ccache
67
64
  tar cf - $(inst_deps) GIT-VERSION-GEN | \
@@ -163,7 +160,7 @@ NEWS: GIT-VERSION-FILE .manifest
163
160
  $(RAKE) -s news_rdoc > $@+
164
161
  mv $@+ $@
165
162
 
166
- SINCE = 0.95.0
163
+ SINCE = 0.96.0
167
164
  ChangeLog: LOG_VERSION = \
168
165
  $(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
169
166
  echo $(GIT_VERSION) || git describe)
@@ -286,3 +283,4 @@ gem install-gem: GIT-VERSION-FILE
286
283
  endif
287
284
 
288
285
  .PHONY: .FORCE-GIT-VERSION-FILE doc $(T) $(slow_tests) manifest man
286
+ .PHONY: test-install
@@ -3,6 +3,14 @@
3
3
  Occasionally odd {issues}[link:ISSUES.html] arise without a transparent or
4
4
  acceptable solution. Those issues are documented here.
5
5
 
6
+ * When using "preload_app true", with apps using background threads
7
+ need to restart them in the after_fork hook because threads are never
8
+ shared with child processes. Additionally, any synchronization
9
+ primitives (Mutexes, Monitors, ConditionVariables) should be
10
+ reinitialized in case they are held during fork time to avoid
11
+ deadlocks. The core Ruby Logger class needlessly uses a MonitorMutex
12
+ which can be disabled with a {monkey patch}[link:examples/logger_mp_safe.rb]
13
+
6
14
  * Rails 2.3.2 bundles its own version of Rack. This may cause subtle
7
15
  bugs when simultaneously loaded with the system-wide Rack Rubygem
8
16
  which Unicorn depends on. Upgrading to Rails 2.3.4 (or later) is
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
1
  # -*- encoding: binary -*-
2
+ autoload :Gem, 'rubygems'
2
3
 
3
4
  # most tasks are in the GNUmakefile which offers better parallelism
4
5
 
@@ -94,8 +95,6 @@ end
94
95
 
95
96
  desc "print release notes for Rubyforge"
96
97
  task :release_notes do
97
- require 'rubygems'
98
-
99
98
  spec = Gem::Specification.load('unicorn.gemspec')
100
99
  puts spec.description.strip
101
100
  puts ""
@@ -110,7 +109,6 @@ end
110
109
 
111
110
  desc "post to RAA"
112
111
  task :raa_update do
113
- require 'rubygems'
114
112
  require 'net/http'
115
113
  require 'net/netrc'
116
114
  rc = Net::Netrc.locate('unicorn-raa') or abort "~/.netrc not found"
@@ -177,7 +175,6 @@ end
177
175
 
178
176
  # optional rake-compiler support in case somebody needs to cross compile
179
177
  begin
180
- require 'rubygems'
181
178
  spec = Gem::Specification.load('unicorn.gemspec')
182
179
  require 'rake/extensiontask'
183
180
  unless test ?r, "ext/unicorn_http/unicorn_http.c"
data/TODO CHANGED
@@ -1,10 +1,5 @@
1
1
  * Documentation improvements
2
2
 
3
- * ensure test suite passes on non-GNU/Linux systems
4
- (likely that it already does)
5
-
6
- * fix const-correctness in HTTP parser
7
-
8
3
  * performance validation (esp. TeeInput)
9
4
 
10
- * improve test suite (steal from Rainbows!, probably...)
5
+ * improve test suite
@@ -108,52 +108,14 @@ opts = OptionParser.new("", 24, ' ') do |opts|
108
108
  opts.parse! ARGV
109
109
  end
110
110
 
111
- config = ARGV[0] || "config.ru"
112
- abort "configuration file #{config} not found" unless File.exist?(config)
113
-
114
- if config =~ /\.ru$/
115
- # parse embedded command-line options in config.ru comments
116
- if File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) } =~ /^#\\(.*)/
117
- opts.parse! $1.split(/\s+/)
118
- end
119
- end
120
-
121
- require 'pp' if $DEBUG
122
-
123
- app = lambda do ||
124
- # require Rack as late as possible in case $LOAD_PATH is modified
125
- # in config.ru or command-line
126
- inner_app = case config
127
- when /\.ru$/
128
- raw = File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) }
129
- raw.sub!(/^__END__\n.*/, '')
130
- eval("Rack::Builder.new {(#{raw}\n)}.to_app", nil, config)
131
- else
132
- require config
133
- Object.const_get(File.basename(config, '.rb').capitalize)
134
- end
135
- pp({ :inner_app => inner_app }) if $DEBUG
136
- case ENV["RACK_ENV"]
137
- when "development"
138
- Rack::Builder.new do
139
- use Rack::CommonLogger, $stderr
140
- use Rack::ShowExceptions
141
- use Rack::Lint
142
- run inner_app
143
- end.to_app
144
- when "deployment"
145
- Rack::Builder.new do
146
- use Rack::CommonLogger, $stderr
147
- run inner_app
148
- end.to_app
149
- else
150
- inner_app
151
- end
152
- end
111
+ ru = ARGV[0] || "config.ru"
112
+ abort "configuration file #{ru} not found" unless File.exist?(ru)
153
113
 
114
+ app = Unicorn.builder(ru, opts)
154
115
  listeners << "#{host}:#{port}" if set_listener
155
116
 
156
117
  if $DEBUG
118
+ require 'pp'
157
119
  pp({
158
120
  :unicorn_options => options,
159
121
  :app => app,
@@ -4,8 +4,6 @@ require 'unicorn/launcher'
4
4
  require 'optparse'
5
5
  require 'fileutils'
6
6
 
7
- rails_pid = "#{Unicorn::HttpServer::START_CTX[:cwd]}/tmp/pids/unicorn.pid"
8
- cmd = File.basename($0)
9
7
  daemonize = false
10
8
  listeners = []
11
9
  options = { :listeners => listeners }
@@ -14,6 +12,7 @@ set_listener = false
14
12
  ENV['RAILS_ENV'] ||= "development"
15
13
 
16
14
  opts = OptionParser.new("", 24, ' ') do |opts|
15
+ cmd = File.basename($0)
17
16
  opts.banner = "Usage: #{cmd} " \
18
17
  "[ruby options] [#{cmd} options] [rackup config file]"
19
18
  opts.separator "Ruby options:"
@@ -111,83 +110,81 @@ end
111
110
 
112
111
  config = ARGV[0] || (File.exist?('config.ru') ? 'config.ru' : nil)
113
112
 
114
- if config && config =~ /\.ru$/
113
+ if config && config =~ /\.ru\z/
115
114
  # parse embedded command-line options in config.ru comments
116
- if File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) } =~ /^#\\(.*)/
117
- opts.parse! $1.split(/\s+/)
118
- end
115
+ /^#\\(.*)/ =~ File.read(config) and opts.parse!($1.split(/\s+/))
119
116
  end
120
117
 
121
- require 'pp' if $DEBUG
122
-
123
- # this won't run until after forking if preload_app is false
124
- app = lambda do ||
125
- # Load Rails and the private version of Rack it bundles.
126
- begin
127
- require 'config/boot'
128
- rescue LoadError => err
129
- abort "#$0 must be run inside RAILS_ROOT: #{err.inspect}"
130
- end
131
- defined?(::RAILS_ROOT) or abort "RAILS_ROOT not defined by config/boot"
132
- defined?(::RAILS_ENV) or abort "RAILS_ENV not defined by config/boot"
133
- defined?(::Rails::VERSION::STRING) or
134
- abort "Rails::VERSION::STRING not defined by config/boot"
135
-
136
- inner_app = case config
137
- when nil
138
- require 'config/environment'
139
-
140
- # it seems Rails >=2.2 support Rack, but only >=2.3 requires it
141
- old_rails = case ::Rails::VERSION::MAJOR
142
- when 0, 1 then true
143
- when 2 then Rails::VERSION::MINOR < 3 ? true : false
144
- else
145
- false
118
+ def rails_builder(config, daemonize)
119
+ # this lambda won't run until after forking if preload_app is false
120
+ lambda do ||
121
+ # Load Rails and (possibly) the private version of Rack it bundles.
122
+ begin
123
+ require 'config/boot'
124
+ rescue LoadError => err
125
+ abort "#$0 must be run inside RAILS_ROOT: #{err.inspect}"
146
126
  end
147
127
 
148
- if old_rails
149
- require 'unicorn/app/old_rails'
150
- Unicorn::App::OldRails.new
151
- else
152
- ActionController::Dispatcher.new
153
- end
154
- when /\.ru$/
155
- raw = File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) }
156
- raw.sub!(/^__END__\n.*/, '')
157
- eval("Rack::Builder.new {(#{raw}\n)}.to_app", nil, config)
158
- else
159
- require config
160
- Object.const_get(File.basename(config, '.rb').capitalize)
161
- end
162
-
163
- Rack::Builder.new do
164
- map_path = ENV['RAILS_RELATIVE_URL_ROOT'] || '/'
165
- if inner_app.class.to_s == "Unicorn::App::OldRails"
166
- if map_path != '/'
167
- # patches + tests welcome, but I really cbf to deal with this
168
- # since all apps I've ever dealt with just use "/" ...
169
- $stderr.puts "relative URL roots may not work for older Rails"
128
+ inner_app = case config
129
+ when nil
130
+ require 'config/environment'
131
+
132
+ defined?(::Rails::VERSION::STRING) or
133
+ abort "Rails::VERSION::STRING not defined by config/{boot,environment}"
134
+ # it seems Rails >=2.2 support Rack, but only >=2.3 requires it
135
+ old_rails = case ::Rails::VERSION::MAJOR
136
+ when 0, 1 then true
137
+ when 2 then Rails::VERSION::MINOR < 3 ? true : false
138
+ else
139
+ false
170
140
  end
171
- $stderr.puts "LogTailer not available for Rails < 2.3" unless daemonize
172
- $stderr.puts "Debugger not available" if $DEBUG
173
- map(map_path) do
174
- use Unicorn::App::OldRails::Static
175
- run inner_app
141
+
142
+ if old_rails
143
+ require 'unicorn/app/old_rails'
144
+ Unicorn::App::OldRails.new
145
+ else
146
+ ActionController::Dispatcher.new
176
147
  end
148
+ when /\.ru$/
149
+ raw = File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) }
150
+ raw.sub!(/^__END__\n.*/, '')
151
+ eval("Rack::Builder.new {(#{raw}\n)}.to_app", nil, config)
177
152
  else
178
- use Rails::Rack::LogTailer unless daemonize
179
- use Rails::Rack::Debugger if $DEBUG
180
- map(map_path) do
181
- use Rails::Rack::Static
182
- run inner_app
183
- end
153
+ require config
154
+ Object.const_get(File.basename(config, '.rb').capitalize)
184
155
  end
185
- end.to_app
156
+
157
+ Rack::Builder.new do
158
+ map_path = ENV['RAILS_RELATIVE_URL_ROOT'] || '/'
159
+ if inner_app.class.to_s == "Unicorn::App::OldRails"
160
+ if map_path != '/'
161
+ # patches + tests welcome, but I really cbf to deal with this
162
+ # since all apps I've ever dealt with just use "/" ...
163
+ $stderr.puts "relative URL roots may not work for older Rails"
164
+ end
165
+ $stderr.puts "LogTailer not available for Rails < 2.3" unless daemonize
166
+ $stderr.puts "Debugger not available" if $DEBUG
167
+ map(map_path) do
168
+ use Unicorn::App::OldRails::Static
169
+ run inner_app
170
+ end
171
+ else
172
+ use Rails::Rack::LogTailer unless daemonize
173
+ use Rails::Rack::Debugger if $DEBUG
174
+ map(map_path) do
175
+ use Rails::Rack::Static
176
+ run inner_app
177
+ end
178
+ end
179
+ end.to_app
180
+ end
186
181
  end
187
182
 
183
+ app = rails_builder(config, daemonize)
188
184
  listeners << "#{host}:#{port}" if set_listener
189
185
 
190
186
  if $DEBUG
187
+ require 'pp'
191
188
  pp({
192
189
  :unicorn_options => options,
193
190
  :app => app,
@@ -196,12 +193,12 @@ if $DEBUG
196
193
  end
197
194
 
198
195
  # ensure Rails standard tmp paths exist
199
- %w(cache pids sessions sockets).each do |dir|
200
- FileUtils.mkdir_p("tmp/#{dir}")
196
+ options[:after_reload] = lambda do
197
+ FileUtils.mkdir_p(%w(cache pids sessions sockets).map! { |d| "tmp/#{d}" })
201
198
  end
202
199
 
203
200
  if daemonize
204
- options[:pid] = rails_pid
201
+ options[:pid] = "tmp/pids/unicorn.pid"
205
202
  Unicorn::Launcher.daemonize!(options)
206
203
  end
207
204
  Unicorn.run(app, options)
@@ -8,6 +8,8 @@ APP_ROOT=/home/x/my_app/current
8
8
  PID=$APP_ROOT/tmp/pids/unicorn.pid
9
9
  CMD="/usr/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb"
10
10
  INIT_CONF=$APP_ROOT/config/init.conf
11
+ action="$1"
12
+ set -u
11
13
 
12
14
  test -f "$INIT_CONF" && . $INIT_CONF
13
15
 
@@ -23,7 +25,7 @@ oldsig () {
23
25
  test -s $old_pid && kill -$1 `cat $old_pid`
24
26
  }
25
27
 
26
- case $1 in
28
+ case $action in
27
29
  start)
28
30
  sig 0 && echo >&2 "Already running" && exit 0
29
31
  $CMD
@@ -46,8 +48,11 @@ upgrade)
46
48
  echo >&2 "Couldn't upgrade, starting '$CMD' instead"
47
49
  $CMD
48
50
  ;;
51
+ reopen-logs)
52
+ sig USR1
53
+ ;;
49
54
  *)
50
- echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop>"
55
+ echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
51
56
  exit 1
52
57
  ;;
53
58
  esac
@@ -0,0 +1,25 @@
1
+ # Multi-Processing-safe monkey patch for Logger
2
+ #
3
+ # This monkey patch fixes the case where "preload_app true" is used and
4
+ # the application spawns a background thread upon being loaded.
5
+ #
6
+ # This removes all lock from the Logger code and solely relies on the
7
+ # underlying filesystem to handle write(2) system calls atomically when
8
+ # O_APPEND is used. This is safe in the presence of both multiple
9
+ # threads (native or green) and multiple processes when writing to
10
+ # a filesystem with POSIX O_APPEND semantics.
11
+ #
12
+ # It should be noted that the original locking on Logger could _never_ be
13
+ # considered reliable on non-POSIX filesystems with multiple processes,
14
+ # either, so nothing is lost in that case.
15
+
16
+ require 'logger'
17
+ class Logger::LogDevice
18
+ def write(message)
19
+ @dev.syswrite(message)
20
+ end
21
+
22
+ def close
23
+ @dev.close
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ # CFLAGS used for development (gcc-dependent)
2
+ # source this file if you want/need them
3
+ CFLAGS=
4
+ CFLAGS="$CFLAGS -Wall"
5
+ CFLAGS="$CFLAGS -Wwrite-strings"
6
+ CFLAGS="$CFLAGS -Wdeclaration-after-statement"
7
+ CFLAGS="$CFLAGS -Wcast-qual"
8
+ CFLAGS="$CFLAGS -Wstrict-prototypes"
9
+ CFLAGS="$CFLAGS -Wshadow"
10
+ CFLAGS="$CFLAGS -Wextra"
11
+ CFLAGS="$CFLAGS -Wno-deprecated-declarations"
12
+ CFLAGS="$CFLAGS -Waggregate-return"
13
+ CFLAGS="$CFLAGS -Wchar-subscripts"