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 +1 -0
- data/Documentation/unicorn_rails.1.txt +6 -1
- data/FAQ +7 -0
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +6 -8
- data/KNOWN_ISSUES +8 -0
- data/Rakefile +1 -4
- data/TODO +1 -6
- data/bin/unicorn +4 -42
- data/bin/unicorn_rails +65 -68
- data/examples/init.sh +7 -2
- data/examples/logger_mp_safe.rb +25 -0
- data/ext/unicorn_http/CFLAGS +13 -0
- data/ext/unicorn_http/c_util.h +13 -0
- data/ext/unicorn_http/common_field_optimization.h +3 -3
- data/ext/unicorn_http/ext_help.h +2 -2
- data/ext/unicorn_http/global_variables.h +1 -3
- data/ext/unicorn_http/unicorn_http.rl +15 -13
- data/lib/unicorn.rb +64 -12
- data/lib/unicorn/configurator.rb +19 -1
- data/lib/unicorn/const.rb +4 -7
- data/lib/unicorn/http_request.rb +1 -1
- data/lib/unicorn/tee_input.rb +39 -39
- data/lib/unicorn/util.rb +1 -2
- data/t/.gitignore +2 -0
- data/t/GNUmakefile +67 -0
- data/t/README +42 -0
- data/t/bin/content-md5-put +36 -0
- data/t/bin/sha1sum.rb +23 -0
- data/t/bin/unused_listen +40 -0
- data/t/bin/utee +12 -0
- data/t/env.ru +3 -0
- data/t/my-tap-lib.sh +200 -0
- data/t/t0000-http-basic.sh +50 -0
- data/t/t0001-reload-bad-config.sh +52 -0
- data/t/t0002-config-conflict.sh +49 -0
- data/t/test-lib.sh +100 -0
- data/test/rails/test_rails.rb +3 -3
- data/test/test_helper.rb +5 -0
- data/test/unit/test_http_parser_ng.rb +0 -1
- data/test/unit/test_server.rb +1 -0
- data/test/unit/test_signals.rb +5 -1
- data/test/unit/test_tee_input.rb +15 -15
- data/test/unit/test_upload.rb +1 -0
- metadata +17 -2
data/.gitignore
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
# NAME
|
6
6
|
|
7
|
-
unicorn_rails - a
|
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
|
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
@@ -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 =
|
13
|
-
RAKE =
|
14
|
-
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.
|
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
|
data/KNOWN_ISSUES
CHANGED
@@ -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
|
5
|
+
* improve test suite
|
data/bin/unicorn
CHANGED
@@ -108,52 +108,14 @@ opts = OptionParser.new("", 24, ' ') do |opts|
|
|
108
108
|
opts.parse! ARGV
|
109
109
|
end
|
110
110
|
|
111
|
-
|
112
|
-
abort "configuration file #{
|
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,
|
data/bin/unicorn_rails
CHANGED
@@ -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
|
-
|
117
|
-
opts.parse! $1.split(/\s+/)
|
118
|
-
end
|
115
|
+
/^#\\(.*)/ =~ File.read(config) and opts.parse!($1.split(/\s+/))
|
119
116
|
end
|
120
117
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
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
|
-
|
179
|
-
|
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
|
-
|
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
|
-
|
200
|
-
FileUtils.mkdir_p("tmp/#{
|
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] =
|
201
|
+
options[:pid] = "tmp/pids/unicorn.pid"
|
205
202
|
Unicorn::Launcher.daemonize!(options)
|
206
203
|
end
|
207
204
|
Unicorn.run(app, options)
|
data/examples/init.sh
CHANGED
@@ -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 $
|
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"
|