rainbows 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/GIT-VERSION-GEN +1 -1
  2. data/TODO +15 -0
  3. data/TUNING +14 -0
  4. data/lib/rainbows.rb +7 -0
  5. data/lib/rainbows/app_pool.rb +4 -3
  6. data/lib/rainbows/base.rb +17 -11
  7. data/lib/rainbows/const.rb +5 -1
  8. data/lib/rainbows/dev_fd_response.rb +69 -0
  9. data/lib/rainbows/http_response.rb +1 -0
  10. data/lib/rainbows/http_server.rb +2 -0
  11. data/lib/rainbows/rev.rb +136 -43
  12. data/lib/rainbows/revactor.rb +6 -14
  13. data/lib/rainbows/thread_pool.rb +11 -13
  14. data/lib/rainbows/thread_spawn.rb +4 -4
  15. data/local.mk.sample +9 -1
  16. data/t/GNUmakefile +4 -4
  17. data/t/README +1 -1
  18. data/t/async-response-no-autochunk.ru +24 -0
  19. data/t/async-response.ru +13 -0
  20. data/t/bin/content-md5-put +1 -1
  21. data/t/bin/utee +12 -0
  22. data/t/env.ru +3 -0
  23. data/t/large-file-response.ru +13 -0
  24. data/t/lib-async-response-no-autochunk.sh +6 -0
  25. data/t/lib-async-response.sh +45 -0
  26. data/t/lib-graceful.sh +40 -0
  27. data/t/lib-input-trailer.sh +63 -0
  28. data/t/lib-large-file-response.sh +45 -0
  29. data/t/lib-parser-error.sh +29 -0
  30. data/t/{t3100-revactor-tee-input.sh → lib-rack-input-hammer.sh} +3 -9
  31. data/t/lib-reopen-logs.sh +60 -0
  32. data/t/lib-simple-http.sh +92 -0
  33. data/t/sleep.ru +13 -6
  34. data/t/t0000-basic.sh +1 -36
  35. data/t/t1000-thread-pool-basic.sh +1 -41
  36. data/t/t1002-thread-pool-graceful.sh +1 -36
  37. data/t/t1003-thread-pool-reopen-logs.sh +2 -0
  38. data/t/t1004-thread-pool-async-response.sh +45 -0
  39. data/t/t1005-thread-pool-large-file-response.sh +45 -0
  40. data/t/t1006-thread-pool-async-response-no-autochunk.sh +6 -0
  41. data/t/t1100-thread-pool-rack-input.sh +2 -0
  42. data/t/t1101-thread-pool-input-trailer.sh +2 -0
  43. data/t/t2000-thread-spawn-basic.sh +1 -37
  44. data/t/t2002-thread-spawn-graceful.sh +1 -36
  45. data/t/t2003-thread-spawn-reopen-logs.sh +2 -0
  46. data/t/t2004-thread-spawn-async-response.sh +45 -0
  47. data/t/t2005-thread-spawn-large-file-response.sh +45 -0
  48. data/t/t2006-thread-spawn-async-response-no-autochunk.sh +6 -0
  49. data/t/t2100-thread-spawn-rack-input.sh +2 -0
  50. data/t/t2101-thread-spawn-input-trailer.sh +2 -0
  51. data/t/t3000-revactor-basic.sh +1 -39
  52. data/t/t3002-revactor-graceful.sh +1 -37
  53. data/t/t3003-revactor-reopen-logs.sh +1 -53
  54. data/t/t3004-revactor-async-response.sh +45 -0
  55. data/t/t3005-revactor-large-file-response.sh +2 -0
  56. data/t/t3006-revactor-async-response-no-autochunk.sh +6 -0
  57. data/t/t3100-revactor-rack-input.sh +2 -0
  58. data/t/t3101-revactor-rack-input-trailer.sh +2 -0
  59. data/t/t4000-rev-basic.sh +1 -50
  60. data/t/t4002-rev-graceful.sh +1 -51
  61. data/t/t4003-rev-parser-error.sh +1 -33
  62. data/t/t4003-rev-reopen-logs.sh +2 -0
  63. data/t/t4004-rev-async-response.sh +45 -0
  64. data/t/t4005-rev-large-file-response.sh +2 -0
  65. data/t/t4006-rev-async-response-no-autochunk.sh +6 -0
  66. data/t/t4100-rev-rack-input.sh +1 -43
  67. data/t/t4101-rev-rack-input-trailer.sh +1 -50
  68. data/t/t9000-rack-app-pool.sh +2 -3
  69. data/t/test-lib.sh +80 -18
  70. metadata +39 -4
  71. data/t/t3001-revactor-pipeline.sh +0 -46
@@ -0,0 +1,45 @@
1
+ . ./test-lib.sh
2
+ test -r random_blob || die "random_blob required, run with 'make $0'"
3
+ if ! grep -v ^VmRSS: /proc/self/status >/dev/null 2>&1
4
+ then
5
+ echo >&2 "skipping, can't read RSS from /proc/self/status"
6
+ exit 0
7
+ fi
8
+ echo "large file response slurp avoidance for model=$model"
9
+ eval $(unused_listen)
10
+ rtmpfiles unicorn_config tmp r_err r_out pid ok
11
+
12
+ cat > $unicorn_config <<EOF
13
+ listen "$listen"
14
+ stderr_path "$r_err"
15
+ stdout_path "$r_out"
16
+ pid "$pid"
17
+ Rainbows! { use :$model }
18
+ EOF
19
+
20
+ # can't load Rack::Lint here since it'll cause Rev to slurp
21
+ rainbows -E none -D large-file-response.ru -c $unicorn_config
22
+ wait_for_pid $pid
23
+
24
+ random_blob_size=$(wc -c < random_blob)
25
+ curl -v http://$listen/rss
26
+ dbgcat r_err
27
+ rss_before=$(curl -sSfv http://$listen/rss)
28
+ echo "rss_before=$rss_before"
29
+
30
+ for i in a b c
31
+ do
32
+ size=$( (curl -sSfv http://$listen/random_blob && echo ok > $ok) | wc -c)
33
+ test $size -eq $random_blob_size
34
+ test xok = x$(cat $ok)
35
+ done
36
+
37
+ dbgcat r_err
38
+ curl -v http://$listen/rss
39
+ rss_after=$(curl -sSfv http://$listen/rss)
40
+ echo "rss_after=$rss_after"
41
+ diff=$(( $rss_after - $rss_before ))
42
+ echo "test diff=$diff < orig=$random_blob_size"
43
+ kill -QUIT $(cat $pid)
44
+ test $diff -le $random_blob_size
45
+ dbgcat r_err
@@ -0,0 +1,29 @@
1
+ . ./test-lib.sh
2
+ echo "parser error test for model=$model"
3
+
4
+ eval $(unused_listen)
5
+ rtmpfiles unicorn_config pid r_err r_out tmp fifo ok
6
+
7
+ cat > $unicorn_config <<EOF
8
+ listen "$listen"
9
+ pid "$pid"
10
+ stderr_path "$r_err"
11
+ stdout_path "$r_out"
12
+ Rainbows! { use :$model }
13
+ EOF
14
+
15
+ rainbows -D env.ru -c $unicorn_config
16
+ wait_for_pid $pid
17
+
18
+ (
19
+ printf 'GET / HTTP/1/1\r\nHost: example.com\r\n\r\n'
20
+ cat $fifo > $tmp &
21
+ wait
22
+ echo ok > $ok
23
+ ) | socat - TCP:$listen > $fifo
24
+
25
+ kill $(cat $pid)
26
+
27
+ dbgcat tmp
28
+ grep -F 'HTTP/1.1 400 Bad Request' $tmp
29
+ check_stderr
@@ -1,9 +1,5 @@
1
- #!/bin/sh
2
- nr_client=${nr_client-25}
3
- nr_actor=${nr_actor-50}
4
-
1
+ nr_client=${nr_client-4}
5
2
  . ./test-lib.sh
6
- require_revactor
7
3
  test -r random_blob || die "random_blob required, run with 'make $0'"
8
4
 
9
5
  eval $(unused_listen)
@@ -15,12 +11,10 @@ pid "$pid"
15
11
  stderr_path "$r_err"
16
12
  stdout_path "$r_out"
17
13
  Rainbows! do
18
- use :Revactor
19
- worker_connections $nr_actor
14
+ use :$model
20
15
  end
21
16
  EOF
22
17
 
23
- echo pid=$pid
24
18
  rainbows -D sha1.ru -c $unicorn_config
25
19
  wait_for_pid $pid
26
20
 
@@ -41,4 +35,4 @@ test 1 -eq $(sort < $curl_out | uniq | wc -l)
41
35
  blob_sha1=$( expr "$(sha1sum < random_blob)" : '\([a-f0-9]\+\)')
42
36
  echo blob_sha1=$blob_sha1
43
37
  test x"$blob_sha1" = x"$(sort < $curl_out | uniq)"
44
- ! grep Error $r_err
38
+ check_stderr
@@ -0,0 +1,60 @@
1
+ #!/bin/sh
2
+ # don't set nr_client for Rev, only _one_ app running at once :x
3
+ nr_client=${nr_client-2}
4
+ . ./test-lib.sh
5
+
6
+ eval $(unused_listen)
7
+ rtmpfiles unicorn_config curl_out curl_err pid r_err r_out r_rot
8
+
9
+
10
+ cat > $unicorn_config <<EOF
11
+ listen "$listen"
12
+ pid "$pid"
13
+ stderr_path "$r_err"
14
+ stdout_path "$r_out"
15
+ Rainbows! { use :$model }
16
+ EOF
17
+
18
+ rainbows -D sleep.ru -c $unicorn_config
19
+ wait_for_pid $pid
20
+
21
+ start=$(date +%s)
22
+ for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
23
+ do
24
+ ( curl -sSf http://$listen/2 >> $curl_out 2>> $curl_err ) &
25
+ done
26
+ check_stderr
27
+
28
+ rm -f $r_rot
29
+ mv $r_err $r_rot
30
+
31
+ kill -USR1 $(cat $pid)
32
+ wait_for_pid $r_err
33
+
34
+ dbgcat r_rot
35
+ dbgcat r_err
36
+
37
+ wait
38
+ echo elapsed=$(( $(date +%s) - $start ))
39
+ test ! -s $curl_err
40
+ test x"$(wc -l < $curl_out)" = x$nr_client
41
+ nr=$(sort < $curl_out | uniq | wc -l)
42
+
43
+ test "$nr" -eq 1
44
+ test x$(sort < $curl_out | uniq) = xHello
45
+ check_stderr
46
+ check_stderr $r_rot
47
+
48
+ before_rot=$(wc -c < $r_rot)
49
+ before_err=$(wc -c < $r_err)
50
+ curl -sSfv http://$listen/
51
+ after_rot=$(wc -c < $r_rot)
52
+ after_err=$(wc -c < $r_err)
53
+
54
+ test $after_rot -eq $before_rot && echo "before_rot -eq after_rot"
55
+ test $after_err -gt $before_err && echo "before_err -gt after_err"
56
+
57
+ kill $(cat $pid)
58
+ dbgcat r_err
59
+ check_stderr
60
+ check_stderr $r_rot
@@ -0,0 +1,92 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ echo "simple HTTP connection keepalive/pipelining tests for $model"
5
+
6
+ tbase=$(expr "$T" : '^\(t....\)-').ru
7
+ test -f "$tbase" || die "$tbase missing for $T"
8
+
9
+ eval $(unused_listen)
10
+ rtmpfiles unicorn_config pid r_err r_out tmp fifo ok
11
+
12
+ cat > $unicorn_config <<EOF
13
+ listen "$listen"
14
+ pid "$pid"
15
+ stderr_path "$r_err"
16
+ stdout_path "$r_out"
17
+ EOF
18
+ if test x$model != xany
19
+ then
20
+ echo "Rainbows! { use :$model }" >> $unicorn_config
21
+ fi
22
+
23
+ rainbows -D $tbase -c $unicorn_config
24
+ wait_for_pid $pid
25
+
26
+ echo "single request"
27
+ curl -sSfv http://$listen/
28
+ dbgcat r_err
29
+
30
+ echo "two requests with keepalive"
31
+ curl -sSfv http://$listen/a http://$listen/b > $tmp 2>&1
32
+ dbgcat r_err
33
+ dbgcat tmp
34
+ grep 'Re-using existing connection' < $tmp
35
+
36
+ echo "pipelining partial requests"
37
+ req='GET / HTTP/1.1\r\nHost: example.com\r\n'
38
+ (
39
+ printf "$req"'\r\n'"$req"
40
+ cat $fifo > $tmp &
41
+ sleep 1
42
+ printf 'Connection: close\r\n\r\n'
43
+ wait
44
+ echo ok > $ok
45
+ ) | socat - TCP:$listen > $fifo
46
+
47
+ dbgcat tmp
48
+
49
+ test 2 -eq $(grep '^HTTP/1.1' $tmp | wc -l)
50
+ test 2 -eq $(grep '^HTTP/1.1 200 OK' $tmp | wc -l)
51
+ test 1 -eq $(grep '^Connection: keep-alive' $tmp | wc -l)
52
+ test 1 -eq $(grep '^Connection: close' $tmp | wc -l)
53
+ test x"$(cat $ok)" = xok
54
+ check_stderr
55
+
56
+
57
+ echo "burst pipelining"
58
+ req='GET / HTTP/1.1\r\nHost: example.com\r\n'
59
+ (
60
+ printf "$req"'\r\n'"$req"'Connection: close\r\n\r\n'
61
+ cat $fifo > $tmp &
62
+ wait
63
+ echo ok > $ok
64
+ ) | socat - TCP:$listen > $fifo
65
+
66
+ dbgcat tmp
67
+ dbgcat r_err
68
+
69
+ test 2 -eq $(grep '^HTTP/1.1' $tmp | wc -l)
70
+ test 2 -eq $(grep '^HTTP/1.1 200 OK' $tmp | wc -l)
71
+ test 1 -eq $(grep '^Connection: keep-alive' $tmp | wc -l)
72
+ test 1 -eq $(grep '^Connection: close' $tmp | wc -l)
73
+ test x"$(cat $ok)" = xok
74
+
75
+ check_stderr
76
+
77
+ echo "HTTP/0.9 request should not return headers"
78
+ (
79
+ printf 'GET /\r\n\r\n'
80
+ cat $fifo > $tmp &
81
+ wait
82
+ echo ok > $ok
83
+ ) | socat - TCP:$listen > $fifo
84
+
85
+ dbgcat tmp
86
+ dbgcat r_err
87
+ echo "env.inspect should've put everything on one line"
88
+ test 1 -eq $(wc -l < $tmp)
89
+ ! grep ^Connection: $tmp
90
+ ! grep ^HTTP/ $tmp
91
+
92
+ kill $(cat $pid)
data/t/sleep.ru CHANGED
@@ -1,11 +1,18 @@
1
1
  use Rack::ContentLength
2
- use Rack::ContentType
3
- sleep_class = ENV['SLEEP_CLASS']
4
- sleep_class = sleep_class ? Object.const_get(sleep_class) : Kernel
5
- $stderr.puts "sleep_class=#{sleep_class.inspect}"
2
+
6
3
  run lambda { |env|
4
+ /\A100-continue\z/i =~ env['HTTP_EXPECT'] and return [ 100, {}, [] ]
5
+
6
+ env['rack.input'].read
7
7
  nr = 1
8
8
  env["PATH_INFO"] =~ %r{/([\d\.]+)\z} and nr = $1.to_f
9
- sleep_class.sleep(nr)
10
- [ 200, {}, [ "Hello\n" ] ]
9
+
10
+ (case env['rainbows.model']
11
+ when :Revactor
12
+ Actor
13
+ else
14
+ Kernel
15
+ end).sleep(nr)
16
+
17
+ [ 200, {'Content-Type' => 'text/plain'}, [ "Hello\n" ] ]
11
18
  }
data/t/t0000-basic.sh CHANGED
@@ -1,37 +1,2 @@
1
1
  #!/bin/sh
2
- . ./test-lib.sh
3
-
4
- eval $(unused_listen)
5
- rtmpfiles pid tmp ok fifo
6
-
7
- rm -f $fifo
8
- mkfifo $fifo
9
-
10
- rainbows -D t0000.ru -l $listen --pid $pid &
11
- wait_for_pid $pid
12
-
13
- echo "single request"
14
- curl -sSfv http://$listen/
15
-
16
- echo "two requests with keepalive"
17
- curl -sSfv http://$listen/a http://$listen/b > $tmp 2>&1
18
- grep 'Re-using existing connection' < $tmp
19
-
20
- echo "pipelining partial requests"
21
- req='GET / HTTP/1.1\r\nHost: foo\r\n'
22
- (
23
- printf "$req"'\r\n'"$req"
24
- cat $fifo > $tmp &
25
- sleep 1
26
- printf 'Connection: close\r\n\r\n'
27
- echo ok > $ok
28
- ) | socat - TCP:$listen > $fifo
29
-
30
- kill $(cat $pid)
31
-
32
- # sed -ne 's/^/------/p' < $tmp
33
- test 2 -eq $(grep '^HTTP/1.1' $tmp | wc -l)
34
- test 2 -eq $(grep '^HTTP/1.1 200 OK' $tmp | wc -l)
35
- test 1 -eq $(grep '^Connection: keep-alive' $tmp | wc -l)
36
- test 1 -eq $(grep '^Connection: close' $tmp | wc -l)
37
- test x"$(cat $ok)" = xok
2
+ . ./lib-simple-http.sh
@@ -1,42 +1,2 @@
1
1
  #!/bin/sh
2
- . ./test-lib.sh
3
-
4
- eval $(unused_listen)
5
- rtmpfiles unicorn_config curl_out curl_err pid r_err r_out
6
-
7
- nr_client=30
8
- nr_thread=10
9
-
10
- cat > $unicorn_config <<EOF
11
- stderr_path "$r_err"
12
- stdout_path "$r_out"
13
- listen "$listen"
14
- pid "$pid"
15
- Rainbows! do
16
- use :ThreadPool
17
- worker_connections $nr_thread
18
- end
19
- EOF
20
-
21
- rainbows -D t1000.ru -c $unicorn_config
22
- wait_for_pid $pid
23
-
24
- start=$(date +%s)
25
- for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
26
- do
27
- ( curl -sSf http://$listen/$i >> $curl_out 2>> $curl_err ) &
28
- done
29
- wait
30
- echo elapsed=$(( $(date +%s) - $start ))
31
-
32
- kill $(cat $pid)
33
-
34
- ! test -s $curl_err
35
- test x"$(wc -l < $curl_out)" = x$nr_client
36
-
37
- nr=$(sort < $curl_out | uniq | wc -l)
38
-
39
- test "$nr" -le $nr_thread
40
- test "$nr" -gt 1
41
-
42
- ! grep Error $r_err
2
+ . ./lib-simple-http.sh
@@ -1,37 +1,2 @@
1
1
  #!/bin/sh
2
- . ./test-lib.sh
3
-
4
- eval $(unused_listen)
5
- rtmpfiles unicorn_config curl_out curl_err pid r_err r_out
6
- nr_thread=10
7
- nr_client=10
8
- cat > $unicorn_config <<EOF
9
- listen "$listen"
10
- stderr_path "$r_err"
11
- stdout_path "$r_out"
12
- pid "$pid"
13
- Rainbows! do
14
- use :ThreadPool
15
- worker_connections $nr_thread
16
- end
17
- EOF
18
-
19
- rainbows -D sleep.ru -c $unicorn_config
20
- wait_for_pid $pid
21
-
22
- for i in $(awk "BEGIN{for(i=0;i<$nr_client;++i) print i}" </dev/null)
23
- do
24
- curl -sSf http://$listen/5 >> $curl_out 2>> $curl_err &
25
- done
26
- sleep 2
27
- kill -QUIT $(cat $pid)
28
- wait
29
-
30
- dbgcat r_err
31
- ! test -s $curl_err
32
- test x"$(wc -l < $curl_out)" = x$nr_client
33
- nr=$(sort < $curl_out | uniq | wc -l)
34
-
35
- test "$nr" -eq 1
36
- test x$(sort < $curl_out | uniq) = xHello
37
- ! grep Error $r_err
2
+ . ./lib-graceful.sh
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ . ./lib-reopen-logs.sh
@@ -0,0 +1,45 @@
1
+ CONFIG_RU=${CONFIG_RU-'async-response.ru'}
2
+ . ./test-lib.sh
3
+ echo "async response for model=$model"
4
+ eval $(unused_listen)
5
+ rtmpfiles unicorn_config a b c r_err r_out pid curl_err
6
+
7
+ cat > $unicorn_config <<EOF
8
+ listen "$listen"
9
+ stderr_path "$r_err"
10
+ stdout_path "$r_out"
11
+ pid "$pid"
12
+ Rainbows! { use :$model }
13
+ EOF
14
+
15
+ # can't load Rack::Lint here since it'll cause Rev to slurp
16
+ rainbows -E none -D $CONFIG_RU -c $unicorn_config
17
+ wait_for_pid $pid
18
+
19
+ t0=$(date +%s)
20
+ ( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $a) &
21
+ ( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $b) &
22
+ ( curl --no-buffer -sSf http://$listen/ 2>> $curl_err | utee $c) &
23
+ wait
24
+ t1=$(date +%s)
25
+
26
+ rainbows_pid=$(cat $pid)
27
+ kill -QUIT $rainbows_pid
28
+ elapsed=$(( $t1 - $t0 ))
29
+ echo "elapsed=$elapsed < 30"
30
+ test $elapsed -lt 30
31
+
32
+ dbgcat a
33
+ dbgcat b
34
+ dbgcat c
35
+ dbgcat r_err
36
+ dbgcat curl_err
37
+ test ! -s $curl_err
38
+ check_stderr
39
+
40
+ while kill -0 $rainbows_pid >/dev/null 2>&1
41
+ do
42
+ sleep 1
43
+ done
44
+
45
+ dbgcat r_err