rainbows 0.2.0 → 0.3.0

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.
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