unicorn 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/lib/unicorn.rb +17 -10
- data/lib/unicorn/configurator.rb +23 -1
- data/lib/unicorn/const.rb +1 -1
- data/lib/unicorn/socket_helper.rb +49 -1
- data/unicorn.gemspec +3 -4
- metadata +3 -3
data/CHANGELOG
CHANGED
data/lib/unicorn.rb
CHANGED
@@ -51,7 +51,7 @@ module Unicorn
|
|
51
51
|
# don't rely on Dir.pwd here since it's not symlink-aware, and
|
52
52
|
# symlink dirs are the default with Capistrano...
|
53
53
|
:cwd => `/bin/sh -c pwd`.chomp("\n"),
|
54
|
-
|
54
|
+
0 => $0.dup,
|
55
55
|
}
|
56
56
|
|
57
57
|
Worker = Struct.new(:nr, :tempfile) unless defined?(Worker)
|
@@ -168,16 +168,23 @@ module Unicorn
|
|
168
168
|
def listen(address, opt = {}.merge(@listener_opts[address] || {}))
|
169
169
|
return if String === address && listener_names.include?(address)
|
170
170
|
|
171
|
-
|
171
|
+
delay, tries = 0.5, 5
|
172
|
+
begin
|
173
|
+
io = bind_listen(address, opt)
|
172
174
|
unless TCPServer === io || UNIXServer === io
|
173
175
|
IO_PURGATORY << io
|
174
176
|
io = server_cast(io)
|
175
177
|
end
|
176
178
|
logger.info "listening on addr=#{sock_name(io)} fd=#{io.fileno}"
|
177
179
|
LISTENERS << io
|
178
|
-
|
180
|
+
return io
|
181
|
+
rescue Errno::EADDRINUSE => err
|
179
182
|
logger.error "adding listener failed addr=#{address} (in use)"
|
180
|
-
raise
|
183
|
+
raise err if tries == 0
|
184
|
+
tries -= 1
|
185
|
+
logger.error "retrying in #{delay} seconds (#{tries} tries left)"
|
186
|
+
sleep(delay)
|
187
|
+
retry
|
181
188
|
end
|
182
189
|
end
|
183
190
|
|
@@ -253,6 +260,7 @@ module Unicorn
|
|
253
260
|
|
254
261
|
# Terminates all workers, but does not exit master process
|
255
262
|
def stop(graceful = true)
|
263
|
+
self.listeners = []
|
256
264
|
kill_each_worker(graceful ? :QUIT : :TERM)
|
257
265
|
timeleft = @timeout
|
258
266
|
step = 0.2
|
@@ -263,8 +271,6 @@ module Unicorn
|
|
263
271
|
(timeleft -= step) > 0 and next
|
264
272
|
kill_each_worker(:KILL)
|
265
273
|
end
|
266
|
-
ensure
|
267
|
-
self.listeners = []
|
268
274
|
end
|
269
275
|
|
270
276
|
private
|
@@ -357,7 +363,7 @@ module Unicorn
|
|
357
363
|
listener_fds = LISTENERS.map { |sock| sock.fileno }
|
358
364
|
ENV['UNICORN_FD'] = listener_fds.join(',')
|
359
365
|
Dir.chdir(START_CTX[:cwd])
|
360
|
-
cmd = [ START_CTX[
|
366
|
+
cmd = [ START_CTX[0] ].concat(START_CTX[:argv])
|
361
367
|
|
362
368
|
# avoid leaking FDs we don't know about, but let before_exec
|
363
369
|
# unset FD_CLOEXEC, if anything else in the app eventually
|
@@ -430,6 +436,7 @@ module Unicorn
|
|
430
436
|
# once a client is accepted, it is processed in its entirety here
|
431
437
|
# in 3 easy steps: read request, call app, write app response
|
432
438
|
def process_client(app, client)
|
439
|
+
client.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
433
440
|
HttpResponse.write(client, app.call(REQUEST.read(client)))
|
434
441
|
# if we get any error, try to write something back to the client
|
435
442
|
# assuming we haven't closed the socket, but don't get hung up
|
@@ -453,7 +460,7 @@ module Unicorn
|
|
453
460
|
# traps for USR1, USR2, and HUP may be set in the @after_fork Proc
|
454
461
|
# by the user.
|
455
462
|
def init_worker_process(worker)
|
456
|
-
QUEUE_SIGS.each { |sig| trap(sig,
|
463
|
+
QUEUE_SIGS.each { |sig| trap(sig, nil) }
|
457
464
|
trap(:CHLD, 'DEFAULT')
|
458
465
|
SIG_QUEUE.clear
|
459
466
|
proc_name "worker[#{worker.nr}]"
|
@@ -609,8 +616,8 @@ module Unicorn
|
|
609
616
|
end
|
610
617
|
|
611
618
|
def proc_name(tag)
|
612
|
-
$0 = ([ File.basename(START_CTX[
|
613
|
-
|
619
|
+
$0 = ([ File.basename(START_CTX[0]), tag
|
620
|
+
]).concat(START_CTX[:argv]).join(' ')
|
614
621
|
end
|
615
622
|
|
616
623
|
def redirect_io(io, path)
|
data/lib/unicorn/configurator.rb
CHANGED
@@ -207,7 +207,24 @@ module Unicorn
|
|
207
207
|
# specified.
|
208
208
|
#
|
209
209
|
# Defaults: operating system defaults
|
210
|
-
|
210
|
+
#
|
211
|
+
# +tcp_nodelay+: disables Nagle's algorithm on TCP sockets
|
212
|
+
#
|
213
|
+
# This has no effect on UNIX sockets.
|
214
|
+
#
|
215
|
+
# Default: operating system defaults (usually Nagle's algorithm enabled)
|
216
|
+
#
|
217
|
+
# +tcp_nopush+: enables TCP_CORK in Linux or TCP_NOPUSH in FreeBSD
|
218
|
+
#
|
219
|
+
# This will prevent partial TCP frames from being sent out.
|
220
|
+
# Enabling +tcp_nopush+ is generally not needed or recommended as
|
221
|
+
# controlling +tcp_nodelay+ already provides sufficient latency
|
222
|
+
# reduction whereas Unicorn does not know when the best times are
|
223
|
+
# for flushing corked sockets.
|
224
|
+
#
|
225
|
+
# This has no effect on UNIX sockets.
|
226
|
+
#
|
227
|
+
def listen(address, opt = {})
|
211
228
|
address = expand_addr(address)
|
212
229
|
if String === address
|
213
230
|
Hash === @set[:listener_opts] or
|
@@ -217,6 +234,11 @@ module Unicorn
|
|
217
234
|
Integer === value or
|
218
235
|
raise ArgumentError, "not an integer: #{key}=#{value.inspect}"
|
219
236
|
end
|
237
|
+
[ :tcp_nodelay, :tcp_nopush ].each do |key|
|
238
|
+
(value = opt[key]).nil? and next
|
239
|
+
TrueClass === value || FalseClass === value or
|
240
|
+
raise ArgumentError, "not boolean: #{key}=#{value.inspect}"
|
241
|
+
end
|
220
242
|
@set[:listener_opts][address].merge!(opt)
|
221
243
|
end
|
222
244
|
|
data/lib/unicorn/const.rb
CHANGED
@@ -5,7 +5,7 @@ module Unicorn
|
|
5
5
|
# gave about a 3% to 10% performance improvement over using the strings directly.
|
6
6
|
# Symbols did not really improve things much compared to constants.
|
7
7
|
module Const
|
8
|
-
UNICORN_VERSION="0.8.
|
8
|
+
UNICORN_VERSION="0.8.2".freeze
|
9
9
|
|
10
10
|
DEFAULT_HOST = "0.0.0.0".freeze # default TCP listen host address
|
11
11
|
DEFAULT_PORT = "8080".freeze # default TCP listen port
|
@@ -4,8 +4,56 @@ module Unicorn
|
|
4
4
|
module SocketHelper
|
5
5
|
include Socket::Constants
|
6
6
|
|
7
|
+
# configure platform-specific options (only tested on Linux 2.6 so far)
|
8
|
+
case RUBY_PLATFORM
|
9
|
+
when /linux/
|
10
|
+
# from /usr/include/linux/tcp.h
|
11
|
+
TCP_DEFER_ACCEPT = 9 unless defined?(TCP_DEFER_ACCEPT)
|
12
|
+
TCP_CORK = 3 unless defined?(TCP_CORK)
|
13
|
+
when /freebsd(([1-4]\..{1,2})|5\.[0-4])/
|
14
|
+
# Do nothing for httpready, just closing a bug when freebsd <= 5.4
|
15
|
+
TCP_NOPUSH = 4 unless defined?(TCP_NOPUSH)
|
16
|
+
when /freebsd/
|
17
|
+
TCP_NOPUSH = 4 unless defined?(TCP_NOPUSH)
|
18
|
+
# Use the HTTP accept filter if available.
|
19
|
+
# The struct made by pack() is defined in /usr/include/sys/socket.h
|
20
|
+
# as accept_filter_arg
|
21
|
+
# We won't be seupportin the "dataready" filter unlike nginx
|
22
|
+
# since we only support HTTP and no other protocols
|
23
|
+
unless `/sbin/sysctl -nq net.inet.accf.http`.empty?
|
24
|
+
HTTPREADY = ['httpready', nil].pack('a16a240').freeze
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_tcp_sockopt(sock, opt)
|
29
|
+
|
30
|
+
# highly portable, but off by default because we don't do keepalive
|
31
|
+
if defined?(TCP_NODELAY) && ! (val = opt[:tcp_nodelay]).nil?
|
32
|
+
sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, val ? 1 : 0) rescue nil
|
33
|
+
end
|
34
|
+
|
35
|
+
unless (val = opt[:tcp_nopush]).nil?
|
36
|
+
val = val ? 1 : 0
|
37
|
+
if defined?(TCP_CORK) # Linux
|
38
|
+
sock.setsockopt(IPPROTO_TCP, TCP_CORK, val) rescue nil
|
39
|
+
elsif defined?(TCP_NOPUSH) # TCP_NOPUSH is untested (FreeBSD)
|
40
|
+
sock.setsockopt(IPPROTO_TCP, TCP_NOPUSH, val) rescue nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# No good reason to ever have deferred accepts off
|
45
|
+
if defined?(TCP_DEFER_ACCEPT)
|
46
|
+
sock.setsockopt(SOL_TCP, TCP_DEFER_ACCEPT, 1) rescue nil
|
47
|
+
elsif defined?(SO_ACCEPTFILTER) && defined?(HTTPREADY)
|
48
|
+
sock.setsockopt(SOL_SOCKET, SO_ACCEPTFILTER, HTTPREADY) rescue nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
7
52
|
def set_server_sockopt(sock, opt)
|
8
53
|
opt ||= {}
|
54
|
+
|
55
|
+
TCPSocket === sock and set_tcp_sockopt(sock, opt)
|
56
|
+
|
9
57
|
if opt[:rcvbuf] || opt[:sndbuf]
|
10
58
|
log_buffer_sizes(sock, "before: ")
|
11
59
|
sock.setsockopt(SOL_SOCKET, SO_RCVBUF, opt[:rcvbuf]) if opt[:rcvbuf]
|
@@ -25,7 +73,7 @@ module Unicorn
|
|
25
73
|
# creates a new server, socket. address may be a HOST:PORT or
|
26
74
|
# an absolute path to a UNIX socket. address can even be a Socket
|
27
75
|
# object in which case it is immediately returned
|
28
|
-
def bind_listen(address = '0.0.0.0:8080', opt = {
|
76
|
+
def bind_listen(address = '0.0.0.0:8080', opt = {})
|
29
77
|
return address unless String === address
|
30
78
|
|
31
79
|
sock = if address[0..0] == "/"
|
data/unicorn.gemspec
CHANGED
@@ -2,23 +2,22 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{unicorn}
|
5
|
-
s.version = "0.8.
|
5
|
+
s.version = "0.8.2"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Eric Wong"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-07-09}
|
10
10
|
s.description = %q{Rack HTTP server for Unix, fast clients and nothing else}
|
11
11
|
s.email = %q{normalperson@yhbt.net}
|
12
12
|
s.executables = ["unicorn", "unicorn_rails"]
|
13
13
|
s.extensions = ["ext/unicorn/http11/extconf.rb"]
|
14
14
|
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "TODO", "bin/unicorn", "bin/unicorn_rails", "ext/unicorn/http11/ext_help.h", "ext/unicorn/http11/extconf.rb", "ext/unicorn/http11/http11.c", "ext/unicorn/http11/http11_parser.h", "ext/unicorn/http11/http11_parser.rl", "ext/unicorn/http11/http11_parser_common.rl", "lib/unicorn.rb", "lib/unicorn/app/exec_cgi.rb", "lib/unicorn/app/old_rails.rb", "lib/unicorn/app/old_rails/static.rb", "lib/unicorn/cgi_wrapper.rb", "lib/unicorn/configurator.rb", "lib/unicorn/const.rb", "lib/unicorn/http_request.rb", "lib/unicorn/http_response.rb", "lib/unicorn/launcher.rb", "lib/unicorn/socket_helper.rb", "lib/unicorn/util.rb"]
|
15
15
|
s.files = [".document", ".gitignore", "CHANGELOG", "CONTRIBUTORS", "DESIGN", "GNUmakefile", "LICENSE", "Manifest", "PHILOSOPHY", "README", "Rakefile", "SIGNALS", "TODO", "TUNING", "bin/unicorn", "bin/unicorn_rails", "examples/init.sh", "ext/unicorn/http11/ext_help.h", "ext/unicorn/http11/extconf.rb", "ext/unicorn/http11/http11.c", "ext/unicorn/http11/http11_parser.h", "ext/unicorn/http11/http11_parser.rl", "ext/unicorn/http11/http11_parser_common.rl", "lib/unicorn.rb", "lib/unicorn/app/exec_cgi.rb", "lib/unicorn/app/old_rails.rb", "lib/unicorn/app/old_rails/static.rb", "lib/unicorn/cgi_wrapper.rb", "lib/unicorn/configurator.rb", "lib/unicorn/const.rb", "lib/unicorn/http_request.rb", "lib/unicorn/http_response.rb", "lib/unicorn/launcher.rb", "lib/unicorn/socket_helper.rb", "lib/unicorn/util.rb", "local.mk.sample", "setup.rb", "test/aggregate.rb", "test/benchmark/README", "test/benchmark/big_request.rb", "test/benchmark/dd.ru", "test/benchmark/request.rb", "test/benchmark/response.rb", "test/exec/README", "test/exec/test_exec.rb", "test/rails/app-1.2.3/.gitignore", "test/rails/app-1.2.3/Rakefile", "test/rails/app-1.2.3/app/controllers/application.rb", "test/rails/app-1.2.3/app/controllers/foo_controller.rb", "test/rails/app-1.2.3/app/helpers/application_helper.rb", "test/rails/app-1.2.3/config/boot.rb", "test/rails/app-1.2.3/config/database.yml", "test/rails/app-1.2.3/config/environment.rb", "test/rails/app-1.2.3/config/environments/development.rb", "test/rails/app-1.2.3/config/environments/production.rb", "test/rails/app-1.2.3/config/routes.rb", "test/rails/app-1.2.3/db/.gitignore", "test/rails/app-1.2.3/log/.gitignore", "test/rails/app-1.2.3/public/404.html", "test/rails/app-1.2.3/public/500.html", "test/rails/app-2.0.2/.gitignore", "test/rails/app-2.0.2/Rakefile", "test/rails/app-2.0.2/app/controllers/application.rb", "test/rails/app-2.0.2/app/controllers/foo_controller.rb", "test/rails/app-2.0.2/app/helpers/application_helper.rb", "test/rails/app-2.0.2/config/boot.rb", "test/rails/app-2.0.2/config/database.yml", "test/rails/app-2.0.2/config/environment.rb", "test/rails/app-2.0.2/config/environments/development.rb", "test/rails/app-2.0.2/config/environments/production.rb", "test/rails/app-2.0.2/config/routes.rb", "test/rails/app-2.0.2/db/.gitignore", "test/rails/app-2.0.2/log/.gitignore", "test/rails/app-2.0.2/public/404.html", "test/rails/app-2.0.2/public/500.html", "test/rails/app-2.1.2/.gitignore", "test/rails/app-2.1.2/Rakefile", "test/rails/app-2.1.2/app/controllers/application.rb", "test/rails/app-2.1.2/app/controllers/foo_controller.rb", "test/rails/app-2.1.2/app/helpers/application_helper.rb", "test/rails/app-2.1.2/config/boot.rb", "test/rails/app-2.1.2/config/database.yml", "test/rails/app-2.1.2/config/environment.rb", "test/rails/app-2.1.2/config/environments/development.rb", "test/rails/app-2.1.2/config/environments/production.rb", "test/rails/app-2.1.2/config/routes.rb", "test/rails/app-2.1.2/db/.gitignore", "test/rails/app-2.1.2/log/.gitignore", "test/rails/app-2.1.2/public/404.html", "test/rails/app-2.1.2/public/500.html", "test/rails/app-2.2.2/.gitignore", "test/rails/app-2.2.2/Rakefile", "test/rails/app-2.2.2/app/controllers/application.rb", "test/rails/app-2.2.2/app/controllers/foo_controller.rb", "test/rails/app-2.2.2/app/helpers/application_helper.rb", "test/rails/app-2.2.2/config/boot.rb", "test/rails/app-2.2.2/config/database.yml", "test/rails/app-2.2.2/config/environment.rb", "test/rails/app-2.2.2/config/environments/development.rb", "test/rails/app-2.2.2/config/environments/production.rb", "test/rails/app-2.2.2/config/routes.rb", "test/rails/app-2.2.2/db/.gitignore", "test/rails/app-2.2.2/log/.gitignore", "test/rails/app-2.2.2/public/404.html", "test/rails/app-2.2.2/public/500.html", "test/rails/app-2.3.2.1/.gitignore", "test/rails/app-2.3.2.1/Rakefile", "test/rails/app-2.3.2.1/app/controllers/application_controller.rb", "test/rails/app-2.3.2.1/app/controllers/foo_controller.rb", "test/rails/app-2.3.2.1/app/helpers/application_helper.rb", "test/rails/app-2.3.2.1/config/boot.rb", "test/rails/app-2.3.2.1/config/database.yml", "test/rails/app-2.3.2.1/config/environment.rb", "test/rails/app-2.3.2.1/config/environments/development.rb", "test/rails/app-2.3.2.1/config/environments/production.rb", "test/rails/app-2.3.2.1/config/routes.rb", "test/rails/app-2.3.2.1/db/.gitignore", "test/rails/app-2.3.2.1/log/.gitignore", "test/rails/app-2.3.2.1/public/404.html", "test/rails/app-2.3.2.1/public/500.html", "test/rails/test_rails.rb", "test/test_helper.rb", "test/unit/test_configurator.rb", "test/unit/test_http_parser.rb", "test/unit/test_request.rb", "test/unit/test_response.rb", "test/unit/test_server.rb", "test/unit/test_signals.rb", "test/unit/test_socket_helper.rb", "test/unit/test_upload.rb", "test/unit/test_util.rb", "unicorn.gemspec"]
|
16
|
-
s.has_rdoc = true
|
17
16
|
s.homepage = %q{http://unicorn.bogomips.org/}
|
18
17
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Unicorn", "--main", "README"]
|
19
18
|
s.require_paths = ["lib", "ext"]
|
20
19
|
s.rubyforge_project = %q{unicorn}
|
21
|
-
s.rubygems_version = %q{1.3.
|
20
|
+
s.rubygems_version = %q{1.3.4}
|
22
21
|
s.summary = %q{Rack HTTP server for Unix, fast clients and nothing else}
|
23
22
|
s.test_files = ["test/unit/test_configurator.rb", "test/unit/test_response.rb", "test/unit/test_request.rb", "test/unit/test_signals.rb", "test/unit/test_upload.rb", "test/unit/test_http_parser.rb", "test/unit/test_socket_helper.rb", "test/unit/test_util.rb", "test/unit/test_server.rb"]
|
24
23
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Wong
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-07-09 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -217,7 +217,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
217
|
requirements: []
|
218
218
|
|
219
219
|
rubyforge_project: unicorn
|
220
|
-
rubygems_version: 1.3.
|
220
|
+
rubygems_version: 1.3.4
|
221
221
|
signing_key:
|
222
222
|
specification_version: 3
|
223
223
|
summary: Rack HTTP server for Unix, fast clients and nothing else
|