rainbows 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.document +1 -0
  2. data/Documentation/GNUmakefile +4 -1
  3. data/Documentation/comparison.css +6 -0
  4. data/Documentation/comparison.haml +297 -0
  5. data/GIT-VERSION-GEN +1 -1
  6. data/GNUmakefile +24 -17
  7. data/README +32 -28
  8. data/Summary +7 -0
  9. data/TODO +4 -6
  10. data/bin/rainbows +2 -2
  11. data/lib/rainbows.rb +33 -3
  12. data/lib/rainbows/actor_spawn.rb +29 -0
  13. data/lib/rainbows/app_pool.rb +17 -6
  14. data/lib/rainbows/base.rb +10 -13
  15. data/lib/rainbows/const.rb +1 -1
  16. data/lib/rainbows/dev_fd_response.rb +6 -0
  17. data/lib/rainbows/error.rb +34 -0
  18. data/lib/rainbows/ev_core.rb +3 -12
  19. data/lib/rainbows/event_machine.rb +7 -9
  20. data/lib/rainbows/fiber.rb +15 -0
  21. data/lib/rainbows/fiber/base.rb +112 -0
  22. data/lib/rainbows/fiber/io.rb +65 -0
  23. data/lib/rainbows/fiber/queue.rb +35 -0
  24. data/lib/rainbows/fiber_pool.rb +44 -0
  25. data/lib/rainbows/fiber_spawn.rb +34 -0
  26. data/lib/rainbows/http_server.rb +14 -1
  27. data/lib/rainbows/never_block.rb +69 -0
  28. data/lib/rainbows/rev.rb +7 -0
  29. data/lib/rainbows/rev/client.rb +9 -3
  30. data/lib/rainbows/rev/core.rb +2 -5
  31. data/lib/rainbows/rev/heartbeat.rb +5 -1
  32. data/lib/rainbows/rev_thread_spawn.rb +62 -60
  33. data/lib/rainbows/revactor.rb +22 -23
  34. data/lib/rainbows/thread_pool.rb +28 -26
  35. data/lib/rainbows/thread_spawn.rb +33 -33
  36. data/local.mk.sample +9 -7
  37. data/rainbows.gemspec +8 -2
  38. data/t/GNUmakefile +14 -7
  39. data/t/fork-sleep.ru +10 -0
  40. data/t/simple-http_FiberPool.ru +9 -0
  41. data/t/simple-http_FiberSpawn.ru +9 -0
  42. data/t/simple-http_NeverBlock.ru +11 -0
  43. data/t/sleep.ru +2 -0
  44. data/t/t0000-simple-http.sh +12 -1
  45. data/t/t0001-unix-http.sh +12 -1
  46. data/t/t0009-broken-app.sh +56 -0
  47. data/t/t0009.ru +13 -0
  48. data/t/t0010-keepalive-timeout-effective.sh +42 -0
  49. data/t/t0011-close-on-exec-set.sh +54 -0
  50. data/t/t0300-async_sinatra.sh +1 -1
  51. data/t/t9000-rack-app-pool.sh +1 -1
  52. data/t/t9000.ru +8 -5
  53. data/t/test-lib.sh +14 -4
  54. metadata +33 -5
  55. data/lib/rainbows/ev_thread_core.rb +0 -80
@@ -0,0 +1,56 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ t_plan 9 "graceful handling of broken apps for $model"
5
+
6
+ t_begin "setup and start" && {
7
+ rainbows_setup $model 1
8
+ rainbows -D t0009.ru -c $unicorn_config
9
+ rainbows_wait_start
10
+ }
11
+
12
+ t_begin "normal response is alright" && {
13
+ test xOK = x"$(curl -sSf http://$listen/)"
14
+ }
15
+
16
+ t_begin "app raised exception" && {
17
+ curl -sSf http://$listen/raise 2> $tmp || :
18
+ grep -F 500 $tmp
19
+ > $tmp
20
+ }
21
+
22
+ t_begin "app exception logged and backtrace not swallowed" && {
23
+ grep -F 'app error' $r_err
24
+ grep -A1 -F 'app error' $r_err | tail -1 | grep t0009.ru:
25
+ dbgcat r_err
26
+ > $r_err
27
+ }
28
+
29
+ t_begin "trigger bad response" && {
30
+ curl -sSf http://$listen/nil 2> $tmp || :
31
+ grep -F 500 $tmp
32
+ > $tmp
33
+ }
34
+
35
+ t_begin "app exception logged" && {
36
+ grep -F 'app error' $r_err
37
+ > $r_err
38
+ }
39
+
40
+ t_begin "normal responses alright afterwards" && {
41
+ > $tmp
42
+ curl -sSf http://$listen/ >> $tmp &
43
+ curl -sSf http://$listen/ >> $tmp &
44
+ curl -sSf http://$listen/ >> $tmp &
45
+ curl -sSf http://$listen/ >> $tmp &
46
+ wait
47
+ test xOK = x$(sort < $tmp | uniq)
48
+ }
49
+
50
+ t_begin "teardown" && {
51
+ kill $rainbows_pid
52
+ }
53
+
54
+ t_begin "check stderr" && check_stderr
55
+
56
+ t_done
data/t/t0009.ru ADDED
@@ -0,0 +1,13 @@
1
+ #\-E none
2
+ # we do not want Rack::Lint or anything to protect us
3
+ use Rack::ContentLength
4
+ use Rack::ContentType, "text/plain"
5
+ map "/" do
6
+ run lambda { |env| [ 200, {}, [ "OK\n" ] ] }
7
+ end
8
+ map "/raise" do
9
+ run lambda { |env| raise "BAD" }
10
+ end
11
+ map "/nil" do
12
+ run lambda { |env| nil }
13
+ end
@@ -0,0 +1,42 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+ t_plan 6 "keepalive_timeout tests for $model"
4
+
5
+ t_begin "setup and start" && {
6
+ rainbows_setup
7
+ rainbows -D env.ru -c $unicorn_config
8
+ rainbows_wait_start
9
+ }
10
+
11
+ t_begin 'check server up' && {
12
+ curl -sSf http://$listen/
13
+ }
14
+
15
+ t_begin "send keepalive response that does not expect close" && {
16
+ req='GET / HTTP/1.1\r\nHost: example.com\r\n\r\n'
17
+ t0=$(date +%s)
18
+ (
19
+ cat $fifo > $tmp &
20
+ printf "$req"
21
+ wait
22
+ date +%s > $ok
23
+ ) | socat - TCP:$listen > $fifo
24
+ now="$(cat $ok)"
25
+ elapsed=$(( $now - $t0 ))
26
+ t_info "elapsed=$elapsed (expecting >=5s)"
27
+ test $elapsed -ge 5
28
+ }
29
+
30
+ t_begin 'keepalive not unreasonably long' && {
31
+ test $elapsed -lt 15
32
+ }
33
+
34
+ t_begin "killing succeeds" && {
35
+ kill $rainbows_pid
36
+ }
37
+
38
+ t_begin "check stderr" && {
39
+ check_stderr
40
+ }
41
+
42
+ t_done
@@ -0,0 +1,54 @@
1
+ #!/bin/sh
2
+ nr=${nr-"5"}
3
+ . ./test-lib.sh
4
+
5
+ t_plan 7 "ensure close-on-exec flag is set for $model"
6
+
7
+ t_begin "setup and start" && {
8
+ rainbows_setup $model 1 1
9
+ nr=$nr rainbows -D fork-sleep.ru -c $unicorn_config
10
+ rainbows_wait_start
11
+ }
12
+
13
+ t_begin "send keepalive req expect it to timeout in ~1s" && {
14
+ req='GET / HTTP/1.1\r\nHost: example.com\r\n\r\n'
15
+ t0=$(date +%s)
16
+ (
17
+ cat $fifo > $tmp &
18
+ printf "$req"
19
+ wait
20
+ date +%s > $ok
21
+ ) | socat - TCP:$listen > $fifo
22
+ now="$(cat $ok)"
23
+ elapsed=$(( $now - $t0 ))
24
+ t_info "elapsed=$elapsed (expecting >=1s)"
25
+ test $elapsed -ge 1
26
+ }
27
+
28
+ t_begin 'sleep process is still running' && {
29
+ sleep_pid="$(tail -1 $tmp)"
30
+ kill -0 $sleep_pid
31
+ }
32
+
33
+ t_begin 'keepalive not unreasonably long' && {
34
+ test $elapsed -lt $nr
35
+ }
36
+
37
+ t_begin "killing succeeds" && {
38
+ kill $rainbows_pid
39
+ }
40
+
41
+ t_begin "check stderr" && {
42
+ t_info "about to start waiting $nr seconds..."
43
+ sleep $nr
44
+ check_stderr
45
+ }
46
+
47
+ t_begin 'sleep process is NOT running' && {
48
+ if kill -0 $sleep_pid
49
+ then
50
+ die "sleep process should've died"
51
+ fi
52
+ }
53
+
54
+ t_done
@@ -5,7 +5,7 @@
5
5
  n=10
6
6
  CONFIG_RU=async_sinatra.ru
7
7
  case $model in
8
- EventMachine) ;;
8
+ NeverBlock|EventMachine) ;;
9
9
  *)
10
10
  t_info "skipping $T since it's not compatible with $model"
11
11
  exit 0
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
  . ./test-lib.sh
3
3
  case $model in
4
- *Thread*) ;;
4
+ *Thread*|*Fiber*|Revactor|NeverBlock) ;;
5
5
  *)
6
6
  t_info "skipping $T since it's not compatible with $model"
7
7
  exit 0
data/t/t9000.ru CHANGED
@@ -1,13 +1,16 @@
1
1
  use Rack::ContentLength
2
2
  use Rack::ContentType
3
3
  use Rainbows::AppPool, :size => ENV['APP_POOL_SIZE'].to_i
4
- sleep_class = ENV['SLEEP_CLASS']
5
- sleep_class = sleep_class ? Object.const_get(sleep_class) : Kernel
6
4
  class Sleeper
7
5
  def call(env)
8
- sleep_class = ENV['SLEEP_CLASS']
9
- sleep_class = sleep_class ? Object.const_get(sleep_class) : Kernel
10
- sleep_class.sleep 1
6
+ (case env['rainbows.model']
7
+ when :FiberPool, :FiberSpawn
8
+ Rainbows::Fiber
9
+ when :Revactor
10
+ Actor
11
+ else
12
+ Kernel
13
+ end).sleep(1)
11
14
  [ 200, {}, [ "#{object_id}\n" ] ]
12
15
  end
13
16
  end
data/t/test-lib.sh CHANGED
@@ -80,7 +80,7 @@ check_stderr () {
80
80
  set +u
81
81
  _r_err=${1-${r_err}}
82
82
  set -u
83
- if grep Error $_r_err
83
+ if grep -i Error $_r_err
84
84
  then
85
85
  die "Errors found in $_r_err"
86
86
  elif grep SIGKILL $_r_err
@@ -115,15 +115,25 @@ before_fork do |server, worker|
115
115
  end
116
116
  EOF
117
117
  {
118
+ # set a higher default for tests since we run heavily-loaded
119
+ # boxes and sometimes sleep 1s in tests
120
+ kato=5
121
+ echo 'Rainbows! do'
118
122
  if test $# -ge 1
119
123
  then
120
- echo 'Rainbows! do'
121
124
  echo " use :$1"
122
125
  test $# -eq 2 && echo " worker_connections $2"
123
- echo end
126
+ if test $# -eq 3
127
+ then
128
+ echo " keepalive_timeout $3"
129
+ else
130
+ echo " keepalive_timeout $kato"
131
+ fi
124
132
  else
125
- echo "Rainbows! { use :$model }"
133
+ echo " use :$model"
134
+ echo " keepalive_timeout $kato"
126
135
  fi
136
+ echo end
127
137
  } >> $unicorn_config
128
138
  }
129
139
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rainbows
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rainbows! hackers
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-15 00:00:00 -08:00
12
+ date: 2009-11-30 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -23,7 +23,7 @@ dependencies:
23
23
  version: 0.95.0
24
24
  version:
25
25
  description: |-
26
- Rainbows! is a HTTP server for sleepy Rack applications. It is based on
26
+ Rainbows! is an HTTP server for sleepy Rack applications. It is based on
27
27
  Unicorn, but designed to handle applications that expect long
28
28
  request/response times and/or slow clients. For Rack applications not
29
29
  heavily bound by slow external network dependencies, consider Unicorn
@@ -38,15 +38,23 @@ extra_rdoc_files:
38
38
  - DEPLOY
39
39
  - FAQ
40
40
  - lib/rainbows.rb
41
+ - lib/rainbows/actor_spawn.rb
41
42
  - lib/rainbows/app_pool.rb
42
43
  - lib/rainbows/base.rb
43
44
  - lib/rainbows/const.rb
44
45
  - lib/rainbows/dev_fd_response.rb
46
+ - lib/rainbows/error.rb
45
47
  - lib/rainbows/ev_core.rb
46
- - lib/rainbows/ev_thread_core.rb
47
48
  - lib/rainbows/event_machine.rb
49
+ - lib/rainbows/fiber.rb
50
+ - lib/rainbows/fiber/base.rb
51
+ - lib/rainbows/fiber/io.rb
52
+ - lib/rainbows/fiber/queue.rb
53
+ - lib/rainbows/fiber_pool.rb
54
+ - lib/rainbows/fiber_spawn.rb
48
55
  - lib/rainbows/http_response.rb
49
56
  - lib/rainbows/http_server.rb
57
+ - lib/rainbows/never_block.rb
50
58
  - lib/rainbows/rev.rb
51
59
  - lib/rainbows/rev/client.rb
52
60
  - lib/rainbows/rev/core.rb
@@ -64,6 +72,7 @@ extra_rdoc_files:
64
72
  - TODO
65
73
  - TUNING
66
74
  - vs_Unicorn
75
+ - Summary
67
76
  files:
68
77
  - .document
69
78
  - .gitignore
@@ -73,6 +82,8 @@ files:
73
82
  - DEPLOY
74
83
  - Documentation/.gitignore
75
84
  - Documentation/GNUmakefile
85
+ - Documentation/comparison.css
86
+ - Documentation/comparison.haml
76
87
  - Documentation/rainbows.1.txt
77
88
  - FAQ
78
89
  - GIT-VERSION-FILE
@@ -83,19 +94,28 @@ files:
83
94
  - README
84
95
  - Rakefile
85
96
  - SIGNALS
97
+ - Summary
86
98
  - TODO
87
99
  - TUNING
88
100
  - bin/rainbows
89
101
  - lib/rainbows.rb
102
+ - lib/rainbows/actor_spawn.rb
90
103
  - lib/rainbows/app_pool.rb
91
104
  - lib/rainbows/base.rb
92
105
  - lib/rainbows/const.rb
93
106
  - lib/rainbows/dev_fd_response.rb
107
+ - lib/rainbows/error.rb
94
108
  - lib/rainbows/ev_core.rb
95
- - lib/rainbows/ev_thread_core.rb
96
109
  - lib/rainbows/event_machine.rb
110
+ - lib/rainbows/fiber.rb
111
+ - lib/rainbows/fiber/base.rb
112
+ - lib/rainbows/fiber/io.rb
113
+ - lib/rainbows/fiber/queue.rb
114
+ - lib/rainbows/fiber_pool.rb
115
+ - lib/rainbows/fiber_spawn.rb
97
116
  - lib/rainbows/http_response.rb
98
117
  - lib/rainbows/http_server.rb
118
+ - lib/rainbows/never_block.rb
99
119
  - lib/rainbows/rev.rb
100
120
  - lib/rainbows/rev/client.rb
101
121
  - lib/rainbows/rev/core.rb
@@ -123,6 +143,7 @@ files:
123
143
  - t/content-md5.ru
124
144
  - t/env.ru
125
145
  - t/env_rack_env.ru
146
+ - t/fork-sleep.ru
126
147
  - t/heartbeat-timeout.ru
127
148
  - t/large-file-response.ru
128
149
  - t/my-tap-lib.sh
@@ -130,6 +151,9 @@ files:
130
151
  - t/sha1.ru
131
152
  - t/simple-http_Base.ru
132
153
  - t/simple-http_EventMachine.ru
154
+ - t/simple-http_FiberPool.ru
155
+ - t/simple-http_FiberSpawn.ru
156
+ - t/simple-http_NeverBlock.ru
133
157
  - t/simple-http_Rev.ru
134
158
  - t/simple-http_RevThreadSpawn.ru
135
159
  - t/simple-http_Revactor.ru
@@ -147,6 +171,10 @@ files:
147
171
  - t/t0006-process-rack-env.sh
148
172
  - t/t0007-worker-follows-master-to-death.sh
149
173
  - t/t0008-ensure-usable-after-limit.sh
174
+ - t/t0009-broken-app.sh
175
+ - t/t0009.ru
176
+ - t/t0010-keepalive-timeout-effective.sh
177
+ - t/t0011-close-on-exec-set.sh
150
178
  - t/t0100-rack-input-hammer.sh
151
179
  - t/t0101-rack-input-trailer.sh
152
180
  - t/t0102-rack-input-short.sh
@@ -1,80 +0,0 @@
1
- # -*- encoding: binary -*-
2
- require 'thread' # for Queue
3
- require 'rainbows/ev_core'
4
-
5
- module Rainbows
6
-
7
- # base module for mixed Thread + evented models like RevThreadSpawn
8
- module EvThreadCore
9
- include EvCore
10
-
11
- def post_init
12
- super
13
- @lock = Mutex.new
14
- @thread = nil
15
- end
16
-
17
- # we pass ourselves off as a Socket to Unicorn::TeeInput and this
18
- # is the only method Unicorn::TeeInput requires from the socket
19
- def readpartial(length, buf = "")
20
- # we must modify the original buffer if there was one
21
- length == 0 and return buf.replace("")
22
-
23
- # wait on the main loop to feed us
24
- while @tbuf.size == 0
25
- @tbuf.write(@state.pop)
26
- resume
27
- end
28
- buf.replace(@tbuf.read(length))
29
- end
30
-
31
- def app_spawn(input)
32
- begin
33
- @thread.nil? or @thread.join # only one thread per connection
34
- env = @env.dup
35
- alive, headers = @hp.keepalive?, @hp.headers?
36
- @thread = Thread.new(self) do |client|
37
- begin
38
- env[REMOTE_ADDR] = @remote_addr
39
- env[RACK_INPUT] = input || TeeInput.new(client, env, @hp, @buf)
40
- response = APP.call(env.update(RACK_DEFAULTS))
41
- if 100 == response.first.to_i
42
- write(EXPECT_100_RESPONSE)
43
- env.delete(HTTP_EXPECT)
44
- response = APP.call(env)
45
- end
46
-
47
- alive &&= G.alive
48
- out = [ alive ? CONN_ALIVE : CONN_CLOSE ] if headers
49
- response_write(response, out)
50
- rescue => e
51
- handle_error(e) rescue nil
52
- end
53
- end
54
- if alive # in case we pipeline
55
- @hp.reset
56
- redo if @hp.headers(@env.clear, @buf)
57
- end
58
- end while false
59
- end
60
-
61
- def on_read(data)
62
- case @state
63
- when :headers
64
- @hp.headers(@env, @buf << data) or return
65
- if 0 == @hp.content_length
66
- app_spawn(HttpRequest::NULL_IO) # common case
67
- else # nil or len > 0
68
- @state, @tbuf = Queue.new, ::IO::Buffer.new
69
- app_spawn(nil)
70
- end
71
- when Queue
72
- pause
73
- @state << data
74
- end
75
- rescue => e
76
- handle_error(e)
77
- end
78
-
79
- end
80
- end