diff options
author | Eric Wong <normalperson@yhbt.net> | 2009-10-18 15:59:29 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2009-10-18 21:25:47 -0700 |
commit | 7b01d94dd9287ac402d91451f1e93c9faaf913c4 (patch) | |
tree | 8f4005f4e92108748af53b8cbf709522f33419db /t | |
parent | d0103759ae63b0ed1084f6a9d2b7ede538e8c871 (diff) | |
download | rainbows-7b01d94dd9287ac402d91451f1e93c9faaf913c4.tar.gz |
This new middleware should be a no-op for non-Rev concurrency models (or by explicitly setting env['rainbows.autochunk'] to false). Setting env['rainbows.autochunk'] to true (the default when Rev is used) allows (e)poll-able IO objects (sockets, pipes) to be sent asynchronously after app.call(env) returns. This also has a fortunate side effect of introducing a code path which allows large, static files to be sent without slurping them into a Rev IO::Buffer, too. This new change works even without the DevFdResponse middleware, so you won't have to reconfigure your app. This lets us epoll on response bodies that come in from a pipe or even a socket and send them either straight through or with chunked encoding.
Diffstat (limited to 't')
-rw-r--r-- | t/async-response-no-autochunk.ru | 24 | ||||
-rw-r--r-- | t/async-response.ru | 13 | ||||
-rw-r--r-- | t/large-file-response.ru | 13 | ||||
-rw-r--r-- | t/lib-async-response-no-autochunk.sh | 6 | ||||
-rw-r--r-- | t/lib-async-response.sh | 45 | ||||
-rw-r--r-- | t/lib-large-file-response.sh | 45 | ||||
l--------- | t/t1004-thread-pool-async-response.sh | 1 | ||||
l--------- | t/t1005-thread-pool-large-file-response.sh | 1 | ||||
l--------- | t/t1006-thread-pool-async-response-no-autochunk.sh | 1 | ||||
l--------- | t/t2004-thread-spawn-async-response.sh | 1 | ||||
l--------- | t/t2005-thread-spawn-large-file-response.sh | 1 | ||||
l--------- | t/t2006-thread-spawn-async-response-no-autochunk.sh | 1 | ||||
l--------- | t/t3004-revactor-async-response.sh | 1 | ||||
-rwxr-xr-x | t/t3005-revactor-large-file-response.sh | 2 | ||||
l--------- | t/t3006-revactor-async-response-no-autochunk.sh | 1 | ||||
l--------- | t/t4004-rev-async-response.sh | 1 | ||||
-rwxr-xr-x | t/t4005-rev-large-file-response.sh | 2 | ||||
l--------- | t/t4006-rev-async-response-no-autochunk.sh | 1 |
18 files changed, 160 insertions, 0 deletions
diff --git a/t/async-response-no-autochunk.ru b/t/async-response-no-autochunk.ru new file mode 100644 index 0000000..67c6403 --- /dev/null +++ b/t/async-response-no-autochunk.ru @@ -0,0 +1,24 @@ +use Rack::Chunked +use Rainbows::DevFdResponse +script = <<-EOF +for i in 0 1 2 3 4 5 6 7 8 9 +do + printf '1\r\n%s\r\n' $i + sleep 1 +done +printf '0\r\n\r\n' +EOF + +run lambda { |env| + env['rainbows.autochunk'] = false + io = IO.popen(script, 'rb') + io.sync = true + [ + 200, + { + 'Content-Type' => 'text/plain', + 'Transfer-Encoding' => 'chunked', + }, + io + ].freeze +} diff --git a/t/async-response.ru b/t/async-response.ru new file mode 100644 index 0000000..ef76504 --- /dev/null +++ b/t/async-response.ru @@ -0,0 +1,13 @@ +use Rack::Chunked +use Rainbows::DevFdResponse +run lambda { |env| + io = IO.popen('for i in 0 1 2 3 4 5 6 7 8 9; do date; sleep 1; done', 'rb') + io.sync = true + [ + 200, + { + 'Content-Type' => 'text/plain', + }, + io + ].freeze +} diff --git a/t/large-file-response.ru b/t/large-file-response.ru new file mode 100644 index 0000000..90dc6c5 --- /dev/null +++ b/t/large-file-response.ru @@ -0,0 +1,13 @@ +# lib-large-file-response will stop running if we're not on Linux here +use Rack::ContentLength +use Rack::ContentType +map "/rss" do + run lambda { |env| + # on Linux, this is in kilobytes + ::File.read("/proc/self/status") =~ /^VmRSS:\s+(\d+)/ + [ 200, {}, [ ($1.to_i * 1024).to_s ] ] + } +end +map "/" do + run Rack::File.new(Dir.pwd) +end diff --git a/t/lib-async-response-no-autochunk.sh b/t/lib-async-response-no-autochunk.sh new file mode 100644 index 0000000..66be85e --- /dev/null +++ b/t/lib-async-response-no-autochunk.sh @@ -0,0 +1,6 @@ +#!/bin/sh +CONFIG_RU=async-response-no-autochunk.ru +. ./lib-async-response.sh +test x"$(cat $a)" = x0123456789 +test x"$(cat $b)" = x0123456789 +test x"$(cat $c)" = x0123456789 diff --git a/t/lib-async-response.sh b/t/lib-async-response.sh new file mode 100644 index 0000000..925455b --- /dev/null +++ b/t/lib-async-response.sh @@ -0,0 +1,45 @@ +CONFIG_RU=${CONFIG_RU-'async-response.ru'} +. ./test-lib.sh +echo "async response for model=$model" +eval $(unused_listen) +rtmpfiles unicorn_config a b c r_err r_out pid curl_err + +cat > $unicorn_config <<EOF +listen "$listen" +stderr_path "$r_err" +stdout_path "$r_out" +pid "$pid" +Rainbows! { use :$model } +EOF + +# can't load Rack::Lint here since it'll cause Rev to slurp +rainbows -E none -D $CONFIG_RU -c $unicorn_config +wait_for_pid $pid + +t0=$(date +%s) +( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $a) & +( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $b) & +( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $c) & +wait +t1=$(date +%s) + +rainbows_pid=$(cat $pid) +kill -QUIT $rainbows_pid +elapsed=$(( $t1 - $t0 )) +echo "elapsed=$elapsed < 30" +test $elapsed -lt 30 + +dbgcat a +dbgcat b +dbgcat c +dbgcat r_err +dbgcat curl_err +test ! -s $curl_err +grep Error $r_err && die "errors in $r_err" + +while kill -0 $rainbows_pid >/dev/null 2>&1 +do + sleep 1 +done + +dbgcat r_err diff --git a/t/lib-large-file-response.sh b/t/lib-large-file-response.sh new file mode 100644 index 0000000..830812a --- /dev/null +++ b/t/lib-large-file-response.sh @@ -0,0 +1,45 @@ +. ./test-lib.sh +test -r random_blob || die "random_blob required, run with 'make $0'" +if ! grep -v ^VmRSS: /proc/self/status >/dev/null 2>&1 +then + echo >&2 "skipping, can't read RSS from /proc/self/status" + exit 0 +fi +echo "large file response slurp avoidance for model=$model" +eval $(unused_listen) +rtmpfiles unicorn_config tmp r_err r_out pid ok + +cat > $unicorn_config <<EOF +listen "$listen" +stderr_path "$r_err" +stdout_path "$r_out" +pid "$pid" +Rainbows! { use :$model } +EOF + +# can't load Rack::Lint here since it'll cause Rev to slurp +rainbows -E none -D large-file-response.ru -c $unicorn_config +wait_for_pid $pid + +random_blob_size=$(wc -c < random_blob) +curl -v http://$listen/rss +dbgcat r_err +rss_before=$(curl -sSfv http://$listen/rss) +echo "rss_before=$rss_before" + +for i in a b c +do + size=$( (curl -sSfv http://$listen/random_blob && echo ok > $ok) | wc -c) + test $size -eq $random_blob_size + test xok = x$(cat $ok) +done + +dbgcat r_err +curl -v http://$listen/rss +rss_after=$(curl -sSfv http://$listen/rss) +echo "rss_after=$rss_after" +diff=$(( $rss_after - $rss_before )) +echo "test diff=$diff < orig=$random_blob_size" +kill -QUIT $(cat $pid) +test $diff -le $random_blob_size +dbgcat r_err diff --git a/t/t1004-thread-pool-async-response.sh b/t/t1004-thread-pool-async-response.sh new file mode 120000 index 0000000..15c27db --- /dev/null +++ b/t/t1004-thread-pool-async-response.sh @@ -0,0 +1 @@ +lib-async-response.sh
\ No newline at end of file diff --git a/t/t1005-thread-pool-large-file-response.sh b/t/t1005-thread-pool-large-file-response.sh new file mode 120000 index 0000000..37d2877 --- /dev/null +++ b/t/t1005-thread-pool-large-file-response.sh @@ -0,0 +1 @@ +lib-large-file-response.sh
\ No newline at end of file diff --git a/t/t1006-thread-pool-async-response-no-autochunk.sh b/t/t1006-thread-pool-async-response-no-autochunk.sh new file mode 120000 index 0000000..bb87ca9 --- /dev/null +++ b/t/t1006-thread-pool-async-response-no-autochunk.sh @@ -0,0 +1 @@ +lib-async-response-no-autochunk.sh
\ No newline at end of file diff --git a/t/t2004-thread-spawn-async-response.sh b/t/t2004-thread-spawn-async-response.sh new file mode 120000 index 0000000..15c27db --- /dev/null +++ b/t/t2004-thread-spawn-async-response.sh @@ -0,0 +1 @@ +lib-async-response.sh
\ No newline at end of file diff --git a/t/t2005-thread-spawn-large-file-response.sh b/t/t2005-thread-spawn-large-file-response.sh new file mode 120000 index 0000000..37d2877 --- /dev/null +++ b/t/t2005-thread-spawn-large-file-response.sh @@ -0,0 +1 @@ +lib-large-file-response.sh
\ No newline at end of file diff --git a/t/t2006-thread-spawn-async-response-no-autochunk.sh b/t/t2006-thread-spawn-async-response-no-autochunk.sh new file mode 120000 index 0000000..bb87ca9 --- /dev/null +++ b/t/t2006-thread-spawn-async-response-no-autochunk.sh @@ -0,0 +1 @@ +lib-async-response-no-autochunk.sh
\ No newline at end of file diff --git a/t/t3004-revactor-async-response.sh b/t/t3004-revactor-async-response.sh new file mode 120000 index 0000000..15c27db --- /dev/null +++ b/t/t3004-revactor-async-response.sh @@ -0,0 +1 @@ +lib-async-response.sh
\ No newline at end of file diff --git a/t/t3005-revactor-large-file-response.sh b/t/t3005-revactor-large-file-response.sh new file mode 100755 index 0000000..ef1a4a3 --- /dev/null +++ b/t/t3005-revactor-large-file-response.sh @@ -0,0 +1,2 @@ +#!/bin/sh +. ./lib-large-file-response.sh diff --git a/t/t3006-revactor-async-response-no-autochunk.sh b/t/t3006-revactor-async-response-no-autochunk.sh new file mode 120000 index 0000000..bb87ca9 --- /dev/null +++ b/t/t3006-revactor-async-response-no-autochunk.sh @@ -0,0 +1 @@ +lib-async-response-no-autochunk.sh
\ No newline at end of file diff --git a/t/t4004-rev-async-response.sh b/t/t4004-rev-async-response.sh new file mode 120000 index 0000000..15c27db --- /dev/null +++ b/t/t4004-rev-async-response.sh @@ -0,0 +1 @@ +lib-async-response.sh
\ No newline at end of file diff --git a/t/t4005-rev-large-file-response.sh b/t/t4005-rev-large-file-response.sh new file mode 100755 index 0000000..ef1a4a3 --- /dev/null +++ b/t/t4005-rev-large-file-response.sh @@ -0,0 +1,2 @@ +#!/bin/sh +. ./lib-large-file-response.sh diff --git a/t/t4006-rev-async-response-no-autochunk.sh b/t/t4006-rev-async-response-no-autochunk.sh new file mode 120000 index 0000000..bb87ca9 --- /dev/null +++ b/t/t4006-rev-async-response-no-autochunk.sh @@ -0,0 +1 @@ +lib-async-response-no-autochunk.sh
\ No newline at end of file |