unicorn 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|