From 1de33f9cdc735588e8dee100e64e68c68b990830 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 25 Apr 2009 12:32:10 -0700 Subject: test_request: enable with Ruby 1.9 now Rack 1.0.0 is out --- test/unit/test_request.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/unit/test_request.rb b/test/unit/test_request.rb index 7c438da..060da24 100644 --- a/test/unit/test_request.rb +++ b/test/unit/test_request.rb @@ -1,11 +1,6 @@ # Copyright (c) 2009 Eric Wong # You can redistribute it and/or modify it under the same terms as Ruby. -if RUBY_VERSION =~ /1\.9/ - warn "#$0 current broken under Ruby 1.9 with Rack" - exit 0 -end - require 'test/test_helper' begin require 'rack' -- cgit v1.2.3-24-ge0c7 From 5bbd75f2bf63d17ef84c7cd156faca278d80bb5b Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 27 Apr 2009 03:47:46 -0700 Subject: test_upload: still uncomfortable with 1.9 IO encoding... It seems most applications use buffered IO#read instead of IO#sysread. So make sure our encoding is set correctly for buffered IO#read applications, too. --- test/unit/test_upload.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/unit/test_upload.rb b/test/unit/test_upload.rb index b06dfdb..9ef3ed7 100644 --- a/test/unit/test_upload.rb +++ b/test/unit/test_upload.rb @@ -19,12 +19,28 @@ class UploadTest < Test::Unit::TestCase @sha1_app = lambda do |env| input = env['rack.input'] resp = { :pos => input.pos, :size => input.size, :class => input.class } + + # sysread @sha1.reset begin loop { @sha1.update(input.sysread(@bs)) } rescue EOFError end resp[:sha1] = @sha1.hexdigest + + # read + input.sysseek(0) if input.respond_to?(:sysseek) + input.rewind + @sha1.reset + loop { + buf = input.read(@bs) or break + @sha1.update(buf) + } + + if resp[:sha1] == @sha1.hexdigest + resp[:sysread_read_byte_match] = true + end + [ 200, @hdr.merge({'X-Resp' => resp.inspect}), [] ] end end @@ -218,6 +234,7 @@ class UploadTest < Test::Unit::TestCase assert $?.success?, 'curl ran OK' assert_match(%r!\b#{sha1}\b!, resp) assert_match(/Tempfile/, resp) + assert_match(/sysread_read_byte_match/, resp) # small StringIO path assert(system("dd", "if=#{@random.path}", "of=#{tmp.path}", @@ -233,6 +250,7 @@ class UploadTest < Test::Unit::TestCase assert $?.success?, 'curl ran OK' assert_match(%r!\b#{sha1}\b!, resp) assert_match(/StringIO/, resp) + assert_match(/sysread_read_byte_match/, resp) end private -- cgit v1.2.3-24-ge0c7 From 772127fca59290327344e3851cbf5b0e5a4ce2df Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 29 Apr 2009 11:53:00 -0700 Subject: Add example init script This was done in Bourne shell because it's easier for UNIX sysadmins who don't know Ruby to understand and modify. Additionally, it can be used for nginx or anything else that shares compatible signal handling. --- examples/init.sh | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 examples/init.sh diff --git a/examples/init.sh b/examples/init.sh new file mode 100644 index 0000000..866a644 --- /dev/null +++ b/examples/init.sh @@ -0,0 +1,54 @@ +#!/bin/sh +set -u +set -e +# Example init script, this can be used with nginx, too, +# since nginx and unicorn accept the same signals + +# Feel free to change any of the following variables for your app: +APP_ROOT=/home/x/my_app/current +PID=$APP_ROOT/tmp/pids/unicorn.pid +CMD="/usr/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb" +INIT_CONF=$APP_ROOT/config/init.conf + +test -f "$INIT_CONF" && . $INIT_CONF + +old_pid="$PID.oldbin" + +cd $APP_ROOT || exit 1 + +sig () { + test -s "$PID" && kill -$1 `cat $PID` +} + +oldsig () { + test -s $old_pid && kill -$1 `cat $old_pid` +} + +case $1 in +start) + sig 0 && echo >&2 "Already running" && exit 0 + $CMD + ;; +stop) + sig QUIT && exit 0 + echo >&2 "Not running" + ;; +force-stop) + sig TERM && exit 0 + echo >&2 "Not running" + ;; +restart|reload) + sig HUP && echo reloaded OK && exit 0 + echo >&2 "Couldn't reload, starting '$CMD' instead" + $CMD + ;; +upgrade) + sig USR2 && sleep 2 && sig 0 && oldsig QUIT && exit 0 + echo >&2 "Couldn't upgrade, starting '$CMD' instead" + $CMD + ;; +*) + echo >&2 "Usage: $0 " + exit 1 + ;; +esac -- cgit v1.2.3-24-ge0c7 From df330c00577fed3c16be92129891f08f56441aef Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 2 May 2009 22:43:22 -0700 Subject: app/exec_cgi: GC prevention Don't allow newly created IO objects to get GC'ed and subsequently close(2)-ed. We're not reopening the {$std,STD}{in,out,err} variables since those can't be trusted to have fileno 1, 2 and 3 respectively. --- lib/unicorn/app/exec_cgi.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/unicorn/app/exec_cgi.rb b/lib/unicorn/app/exec_cgi.rb index f5e7db9..d98b3e4 100644 --- a/lib/unicorn/app/exec_cgi.rb +++ b/lib/unicorn/app/exec_cgi.rb @@ -69,9 +69,9 @@ module Unicorn::App ENV['GATEWAY_INTERFACE'] = 'CGI/1.1' env.keys.grep(/^HTTP_/) { |key| ENV[key] = env[key] } - IO.new(0).reopen(inp) - IO.new(1).reopen(out) - IO.new(2).reopen(err) + a = IO.new(0).reopen(inp) + b = IO.new(1).reopen(out) + c = IO.new(2).reopen(err) exec(*@args) end -- cgit v1.2.3-24-ge0c7 From 4b50c7d814f770347b96b8b1fa52ff41656670ec Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 2 May 2009 23:40:07 -0700 Subject: Add TUNING document Most of this should be applicable to Mongrel and other web servers, too. --- .document | 1 + Manifest | 2 ++ TUNING | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 TUNING diff --git a/.document b/.document index 432d4bb..e8ef088 100644 --- a/.document +++ b/.document @@ -1,4 +1,5 @@ README +TUNING PHILOSOPHY DESIGN CONTRIBUTORS diff --git a/Manifest b/Manifest index 4a9f9cf..cfc2ddb 100644 --- a/Manifest +++ b/Manifest @@ -11,8 +11,10 @@ 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 diff --git a/TUNING b/TUNING new file mode 100644 index 0000000..c0f633b --- /dev/null +++ b/TUNING @@ -0,0 +1,59 @@ += Tuning Unicorn + +Unicorn performance is generally as good as a (mostly) Ruby web server +can provide. Most often the performance bottleneck is in the web +application running on Unicorn rather than Unicorn itself. + +== Unicorn Configuration + +See Unicorn::Configurator for details on the config file format. + +* Setting a very low value for the :backlog parameter in "listen" + directives can allow failover to happen more quickly if your + cluster is configured for it. + +* :rcvbuf and :sndbuf parameters generally do not need to be set for TCP + listeners under Linux 2.6 because auto-tuning is enabled. UNIX domain + sockets do not have auto-tuning buffer sizes; so increasing those will + allow syscalls and task switches to be saved for larger requests + and responses. + +* Setting "preload_app true" can allow copy-on-write-friendly GC to + be used to save memory. It will probably not work out of the box with + applications that open sockets or perform random I/O on files. + Databases like TokyoCabinet use concurrency-safe pread()/pwrite() + functions for safe sharing of database file descriptors across + processes. + +* On POSIX-compliant filesystems, it is safe for multiple threads or + processes to append to one log file as long as all the processes are + have them unbuffered (File#sync = true) or they are + record(line)-buffered in userspace. + +* worker_processes should be scaled to the number of processes your + backend system(s) can support. DO NOT scale it to the number of + external network clients your application expects to be serving. + Unicorn is NOT for serving slow clients, that is the job of nginx. + +== Kernel Parameters (Linux sysctl) + +WARNING: Do not change system parameters unless you know what you're doing! + +* net.core.rmem_max and net.core.wmem_max can increase the allowed + size of :rcvbuf and :sndbuf respectively. This is mostly only useful + for UNIX domain sockets which do not have auto-tuning buffer sizes. + +* If you're running out of local ports, consider lowering + net.ipv4.tcp_fin_timeout to 20-30 (default: 60 seconds). Also + consider widening the usable port range by changing + net.ipv4.ip_local_port_range. + +* Setting net.ipv4.tcp_timestamps=1 will also allow setting + net.ipv4.tcp_tw_reuse=1 and net.ipv4.tcp_tw_recycle=1, which along + with the above settings can slow down port exhaustion. Not all + networks are compatible with these settings, check with your friendly + network administrator before changing these. + +* Increasing the MTU size can reduce framing overhead for larger + transfers. One often-overlooked detail is that the loopback + device (usually "lo") can have its MTU increased, too. -- cgit v1.2.3-24-ge0c7 From 476751e32b8ae454829491ede68f4a062d4cec9f Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 3 May 2009 01:29:14 -0700 Subject: app/old_rails: correctly log errors in output "out" was an invalid variable in that context... --- lib/unicorn/app/old_rails.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/unicorn/app/old_rails.rb b/lib/unicorn/app/old_rails.rb index 4b74666..9b3a3b1 100644 --- a/lib/unicorn/app/old_rails.rb +++ b/lib/unicorn/app/old_rails.rb @@ -19,8 +19,8 @@ class Unicorn::App::OldRails cgi.body) rescue Object => e err = env['rack.errors'] - out.write("#{e} #{e.message}\n") - e.backtrace.each { |line| out.write("#{line}\n") } + err.write("#{e} #{e.message}\n") + e.backtrace.each { |line| err.write("#{line}\n") } end cgi.out # finalize the response cgi.rack_response -- cgit v1.2.3-24-ge0c7 From cfe5234e975b914e831907db77fee8f154950fc1 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 3 May 2009 16:16:48 -0700 Subject: Safer timeout handling and test case Timeouts of less than 2 seconds are unsafe due to the lack of subsecond resolution in most POSIX filesystems. This is the trade-off for using a low-complexity solution for timeouts. Since this type of timeout is a last resort; 2 seconds is not entirely unreasonable IMNSHO. Additionally, timing out too aggressively can put us in a fork loop and slow down the system. Of course, the default is 60 seconds and most people do not bother to change it. --- TODO | 2 -- lib/unicorn.rb | 3 +-- lib/unicorn/configurator.rb | 8 +++++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/TODO b/TODO index 204bb7d..085ef70 100644 --- a/TODO +++ b/TODO @@ -2,8 +2,6 @@ * integration tests with nginx including bad client handling - * tests for timeout - * manpages (why do so few Ruby executables come with proper manpages?) == 1.1.0 diff --git a/lib/unicorn.rb b/lib/unicorn.rb index 54e2bc0..07925f2 100644 --- a/lib/unicorn.rb +++ b/lib/unicorn.rb @@ -375,9 +375,8 @@ module Unicorn # is stale for >@timeout seconds, then we'll kill the corresponding # worker. def murder_lazy_workers - now = Time.now WORKERS.each_pair do |pid, worker| - (now - worker.tempfile.ctime) <= @timeout and next + Time.now - worker.tempfile.ctime <= @timeout and next logger.error "worker=#{worker.nr} PID:#{pid} is too old, killing" kill_worker(:KILL, pid) # take no prisoners for @timeout violations worker.tempfile.close rescue nil diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb index 6f49905..7724ff0 100644 --- a/lib/unicorn/configurator.rb +++ b/lib/unicorn/configurator.rb @@ -143,12 +143,14 @@ module Unicorn # handling the request/app.call/response cycle taking longer than # this time period will be forcibly killed (via SIGKILL). This # timeout is enforced by the master process itself and not subject - # to the scheduling limitations by the worker process. + # to the scheduling limitations by the worker process. Due the + # low-complexity, low-overhead implementation, timeouts of less + # than 2.0 seconds can be considered inaccurate and unsafe. def timeout(seconds) Numeric === seconds or raise ArgumentError, "not numeric: timeout=#{seconds.inspect}" - seconds > 0 or raise ArgumentError, - "not positive: timeout=#{seconds.inspect}" + seconds >= 2 or raise ArgumentError, + "too low: timeout=#{seconds.inspect}" @set[:timeout] = seconds end -- cgit v1.2.3-24-ge0c7 From 99b4c6e1208d39d5938900e3c4f4ebb8f374e08a Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 3 May 2009 13:07:42 -0700 Subject: Ignore unhandled master signals in the workers This makes it easier to use "killall -$SIGNAL unicorn" without having to lookup the correct PID. --- lib/unicorn.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/unicorn.rb b/lib/unicorn.rb index 07925f2..1f7cf8d 100644 --- a/lib/unicorn.rb +++ b/lib/unicorn.rb @@ -443,7 +443,7 @@ module Unicorn # traps for USR1, USR2, and HUP may be set in the @after_fork Proc # by the user. def init_worker_process(worker) - QUEUE_SIGS.each { |sig| trap(sig, 'DEFAULT') } + QUEUE_SIGS.each { |sig| trap(sig, 'IGNORE') } trap(:CHLD, 'DEFAULT') SIG_QUEUE.clear proc_name "worker[#{worker.nr}]" -- cgit v1.2.3-24-ge0c7 From 721be5f0d1874da3e623b4eeea81952909fdfee2 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 3 May 2009 20:35:36 -0700 Subject: TUNING: add a note about somaxconn with UNIX sockets --- TUNING | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TUNING b/TUNING index c0f633b..6445fd4 100644 --- a/TUNING +++ b/TUNING @@ -43,6 +43,10 @@ WARNING: Do not change system parameters unless you know what you're doing! size of :rcvbuf and :sndbuf respectively. This is mostly only useful for UNIX domain sockets which do not have auto-tuning buffer sizes. +* For load testing/benchmarking with UNIX domain sockets, you should + consider increasing net.core.somaxconn or else nginx will start + failing to connect under heavy load. + * If you're running out of local ports, consider lowering net.ipv4.tcp_fin_timeout to 20-30 (default: 60 seconds). Also consider widening the usable port range by changing -- cgit v1.2.3-24-ge0c7 From 3d2b5954d70af6abd713bc820b3d7bc1ea115f30 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 4 May 2009 05:21:18 +0000 Subject: Fix a warning about @pid being uninitialized --- lib/unicorn.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/unicorn.rb b/lib/unicorn.rb index 1f7cf8d..f5c1c8c 100644 --- a/lib/unicorn.rb +++ b/lib/unicorn.rb @@ -64,6 +64,7 @@ module Unicorn # incoming requests on the socket. def initialize(app, options = {}) @app = app + @pid = nil @reexec_pid = 0 @init_listeners = options[:listeners] ? options[:listeners].dup : [] @config = Configurator.new(options.merge(:use_defaults => true)) -- cgit v1.2.3-24-ge0c7 From 95718a5769e4ab06c86d0531e8a7c70fbd4c2f81 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 4 May 2009 02:01:32 -0700 Subject: Preserve 1.9 IO encodings in reopen_logs Ensure we preserve both internal and external encodings when reopening logs. --- Manifest | 1 + lib/unicorn/util.rb | 15 ++++++--- test/unit/test_util.rb | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 test/unit/test_util.rb diff --git a/Manifest b/Manifest index cfc2ddb..89db23c 100644 --- a/Manifest +++ b/Manifest @@ -129,3 +129,4 @@ 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 diff --git a/lib/unicorn/util.rb b/lib/unicorn/util.rb index 0400fd0..2d3f827 100644 --- a/lib/unicorn/util.rb +++ b/lib/unicorn/util.rb @@ -4,6 +4,8 @@ module Unicorn class Util class << self + APPEND_FLAGS = File::WRONLY | File::APPEND + # this reopens logs that have been rotated (using logrotate(8) or # similar). It is recommended that you install # A +File+ object is considered for reopening if it is: @@ -17,17 +19,20 @@ module Unicorn ObjectSpace.each_object(File) do |fp| next if fp.closed? next unless (fp.sync && fp.path[0..0] == "/") - - flags = fp.fcntl(Fcntl::F_GETFL) - open_flags = File::WRONLY | File::APPEND - next unless (flags & open_flags) == open_flags + next unless (fp.fcntl(Fcntl::F_GETFL) & APPEND_FLAGS) == APPEND_FLAGS begin a, b = fp.stat, File.stat(fp.path) next if a.ino == b.ino && a.dev == b.dev rescue Errno::ENOENT end - fp.reopen(fp.path, "a") + + open_arg = 'a' + if fp.respond_to?(:external_encoding) && enc = fp.external_encoding + open_arg << ":#{enc.to_s}" + enc = fp.internal_encoding and open_arg << ":#{enc.to_s}" + end + fp.reopen(fp.path, open_arg) fp.sync = true nr += 1 end # each_object diff --git a/test/unit/test_util.rb b/test/unit/test_util.rb new file mode 100644 index 0000000..1616eac --- /dev/null +++ b/test/unit/test_util.rb @@ -0,0 +1,87 @@ +require 'test/test_helper' +require 'tempfile' + +class TestUtil < Test::Unit::TestCase + + EXPECT_FLAGS = File::WRONLY | File::APPEND + def test_reopen_logs_noop + tmp = Tempfile.new(nil) + tmp.reopen(tmp.path, 'a') + tmp.sync = true + ext = tmp.external_encoding rescue nil + int = tmp.internal_encoding rescue nil + before = tmp.stat.inspect + Unicorn::Util.reopen_logs + assert_equal before, File.stat(tmp.path).inspect + assert_equal ext, (tmp.external_encoding rescue nil) + assert_equal int, (tmp.internal_encoding rescue nil) + end + + def test_reopen_logs_renamed + tmp = Tempfile.new(nil) + tmp_path = tmp.path.freeze + tmp.reopen(tmp_path, 'a') + tmp.sync = true + ext = tmp.external_encoding rescue nil + int = tmp.internal_encoding rescue nil + before = tmp.stat.inspect + to = Tempfile.new(nil) + File.rename(tmp_path, to.path) + assert ! File.exist?(tmp_path) + Unicorn::Util.reopen_logs + assert_equal tmp_path, tmp.path + assert File.exist?(tmp_path) + assert before != File.stat(tmp_path).inspect + assert_equal tmp.stat.inspect, File.stat(tmp_path).inspect + assert_equal ext, (tmp.external_encoding rescue nil) + assert_equal int, (tmp.internal_encoding rescue nil) + assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & tmp.fcntl(Fcntl::F_GETFL)) + assert tmp.sync + end + + def test_reopen_logs_renamed_with_encoding + tmp = Tempfile.new(nil) + tmp_path = tmp.path.dup.freeze + Encoding.list.each { |encoding| + tmp.reopen(tmp_path, "a:#{encoding.to_s}") + tmp.sync = true + assert_equal encoding, tmp.external_encoding + assert_nil tmp.internal_encoding + File.unlink(tmp_path) + assert ! File.exist?(tmp_path) + Unicorn::Util.reopen_logs + assert_equal tmp_path, tmp.path + assert File.exist?(tmp_path) + assert_equal tmp.stat.inspect, File.stat(tmp_path).inspect + assert_equal encoding, tmp.external_encoding + assert_nil tmp.internal_encoding + assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & tmp.fcntl(Fcntl::F_GETFL)) + assert tmp.sync + } + end if STDIN.respond_to?(:external_encoding) + + def test_reopen_logs_renamed_with_internal_encoding + tmp = Tempfile.new(nil) + tmp_path = tmp.path.dup.freeze + Encoding.list.each { |ext| + Encoding.list.each { |int| + next if ext == int + tmp.reopen(tmp_path, "a:#{ext.to_s}:#{int.to_s}") + tmp.sync = true + assert_equal ext, tmp.external_encoding + assert_equal int, tmp.internal_encoding + File.unlink(tmp_path) + assert ! File.exist?(tmp_path) + Unicorn::Util.reopen_logs + assert_equal tmp_path, tmp.path + assert File.exist?(tmp_path) + assert_equal tmp.stat.inspect, File.stat(tmp_path).inspect + assert_equal ext, tmp.external_encoding + assert_equal int, tmp.internal_encoding + assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & tmp.fcntl(Fcntl::F_GETFL)) + assert tmp.sync + } + } + end if STDIN.respond_to?(:external_encoding) + +end -- cgit v1.2.3-24-ge0c7 From 341b6680e021586b1245ec3fb7e6ebf9b75a32f3 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 10 May 2009 19:46:20 -0700 Subject: configurator: fix rdoc formatting --- lib/unicorn/configurator.rb | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb index 7724ff0..64647a3 100644 --- a/lib/unicorn/configurator.rb +++ b/lib/unicorn/configurator.rb @@ -181,32 +181,32 @@ module Unicorn # # +backlog+: this is the backlog of the listen() syscall. # - # Some operating systems allow negative values here to specify the - # maximum allowable value. In most cases, this number is only - # recommendation and there are other OS-specific tunables and - # variables that can affect this number. See the listen(2) - # syscall documentation of your OS for the exact semantics of - # this. + # Some operating systems allow negative values here to specify the + # maximum allowable value. In most cases, this number is only + # recommendation and there are other OS-specific tunables and + # variables that can affect this number. See the listen(2) + # syscall documentation of your OS for the exact semantics of + # this. # - # If you are running unicorn on multiple machines, lowering this number - # can help your load balancer detect when a machine is overloaded - # and give requests to a different machine. + # If you are running unicorn on multiple machines, lowering this number + # can help your load balancer detect when a machine is overloaded + # and give requests to a different machine. # - # Default: 1024 + # Default: 1024 # # +rcvbuf+, +sndbuf+: maximum send and receive buffer sizes of sockets # - # These correspond to the SO_RCVBUF and SO_SNDBUF settings which - # can be set via the setsockopt(2) syscall. Some kernels - # (e.g. Linux 2.4+) have intelligent auto-tuning mechanisms and - # there is no need (and it is sometimes detrimental) to specify them. + # These correspond to the SO_RCVBUF and SO_SNDBUF settings which + # can be set via the setsockopt(2) syscall. Some kernels + # (e.g. Linux 2.4+) have intelligent auto-tuning mechanisms and + # there is no need (and it is sometimes detrimental) to specify them. # - # See the socket API documentation of your operating system - # to determine the exact semantics of these settings and - # other operating system-specific knobs where they can be - # specified. + # See the socket API documentation of your operating system + # to determine the exact semantics of these settings and + # other operating system-specific knobs where they can be + # specified. # - # Defaults: operating system defaults + # Defaults: operating system defaults def listen(address, opt = { :backlog => 1024 }) address = expand_addr(address) if String === address -- cgit v1.2.3-24-ge0c7 From 1e2bbe9f29f2297dacd1f87adedec1033f513aa7 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 10 May 2009 19:02:05 -0700 Subject: Enforce minimum timeout at 3 seconds 2 seconds is still prone to race conditions under high load. We're intentionally less accurate than we could be in order to reduce syscall and method dispatch overhead. --- lib/unicorn/configurator.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb index 64647a3..a432f64 100644 --- a/lib/unicorn/configurator.rb +++ b/lib/unicorn/configurator.rb @@ -145,11 +145,11 @@ module Unicorn # timeout is enforced by the master process itself and not subject # to the scheduling limitations by the worker process. Due the # low-complexity, low-overhead implementation, timeouts of less - # than 2.0 seconds can be considered inaccurate and unsafe. + # than 3.0 seconds can be considered inaccurate and unsafe. def timeout(seconds) Numeric === seconds or raise ArgumentError, "not numeric: timeout=#{seconds.inspect}" - seconds >= 2 or raise ArgumentError, + seconds >= 3 or raise ArgumentError, "too low: timeout=#{seconds.inspect}" @set[:timeout] = seconds end -- cgit v1.2.3-24-ge0c7 From 96122dbcabe96ef0b278c9b5f575ede34d54656a Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 13 May 2009 17:45:37 +0000 Subject: http_response: allow string status codes Rack::Lint says they just have to work when to_i is called on the status, so that's what we'll do. --- lib/unicorn/http_response.rb | 2 +- test/unit/test_response.rb | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/unicorn/http_response.rb b/lib/unicorn/http_response.rb index 5480b5d..f79e856 100644 --- a/lib/unicorn/http_response.rb +++ b/lib/unicorn/http_response.rb @@ -31,7 +31,7 @@ module Unicorn # writes the rack_response to socket as an HTTP response def self.write(socket, rack_response) status, headers, body = rack_response - status = HTTP_STATUS_CODES[status] + status = HTTP_STATUS_CODES[status.to_i] OUT.clear # Don't bother enforcing duplicate supression, it's a Hash most of diff --git a/test/unit/test_response.rb b/test/unit/test_response.rb index 3cb0a41..644a2a7 100644 --- a/test/unit/test_response.rb +++ b/test/unit/test_response.rb @@ -18,6 +18,14 @@ class ResponseTest < Test::Unit::TestCase assert out.length > 0, "output didn't have data" end + def test_response_string_status + out = StringIO.new + HttpResponse.write(out,['200', {}, []]) + assert out.closed? + assert out.length > 0, "output didn't have data" + assert_equal 1, out.string.split(/\r\n/).grep(/^Status: 200 OK/).size + end + def test_response_OFS_set old_ofs = $, $, = "\f\v" -- cgit v1.2.3-24-ge0c7 From 87a27a9c0d59df291b1ce4dbce2c6eb4dbf26709 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Wed, 13 May 2009 17:47:23 +0000 Subject: test_response: correct OFS test Must have multiple headers to test this effectively --- test/unit/test_response.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_response.rb b/test/unit/test_response.rb index 644a2a7..66c2b54 100644 --- a/test/unit/test_response.rb +++ b/test/unit/test_response.rb @@ -30,7 +30,7 @@ class ResponseTest < Test::Unit::TestCase old_ofs = $, $, = "\f\v" out = StringIO.new - HttpResponse.write(out,[200, {"X-Whatever" => "stuff"}, ["cool"]]) + HttpResponse.write(out,[200, {"X-k" => "cd","X-y" => "z"}, ["cool"]]) assert out.closed? resp = out.string assert ! resp.include?("\f\v"), "output didn't use $, ($OFS)" -- cgit v1.2.3-24-ge0c7 From 0d726281fe276ea36007ae9715d9085cede8d04c Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 21 May 2009 10:42:42 -0700 Subject: Disable formatting for command-line switches Copy and pasting from the RDoc web page and passing "\342\200\224config-file" to the command-line does not work. --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index c12dbf2..5a4c89c 100644 --- a/README +++ b/README @@ -103,7 +103,7 @@ In RAILS_ROOT, run: unicorn_rails Unicorn will bind to all interfaces TCP port 8080 by default. -You may use the '-l/--listen' switch to bind to a different +You may use the +-l/--listen+ switch to bind to a different address:port or a UNIX socket. === Configuration File(s) @@ -111,7 +111,7 @@ address:port or a UNIX socket. Unicorn will look for the config.ru file used by rackup in APP_ROOT. For deployments, it can use a config file for Unicorn-specific options -specified by the --config-file/-c command-line switch. See +specified by the +--config-file/-c+ command-line switch. See Unicorn::Configurator for the syntax of the Unicorn-specific options. The default settings are designed for maximum out-of-the-box compatibility with existing applications. -- cgit v1.2.3-24-ge0c7 From 5d11428632bf40d3c20313f56085dfd4921c1265 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 21 May 2009 11:33:16 -0700 Subject: GNUmakefile: glob all files in bin/* Easier to maintain and add new executables this way --- GNUmakefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index 6beed35..1145143 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -53,8 +53,10 @@ $(test_prefix)/.stamp: $(inst_deps) $(MAKE) -C $(test_prefix) http11 shebang > $@ +bins := $(wildcard bin/*) + # this is only intended to be run within $(test_prefix) -shebang: bin/unicorn bin/unicorn_rails +shebang: $(bins) $(ruby) -i -p -e '$$_.gsub!(%r{^#!.*$$},"#!$(ruby_bin)")' $^ t_log := $(T_log) $(T_n_log) @@ -97,7 +99,7 @@ $(T): export RUBYLIB := $(test_prefix)/lib:$(RUBYLIB) $(T): $(test_prefix)/.stamp $(run_test) -install: bin/unicorn bin/unicorn_rails +install: $(bins) $(prep_setup_rb) $(RM) -r .install-tmp mkdir .install-tmp -- cgit v1.2.3-24-ge0c7