rainbows 0.6.0 → 0.7.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 (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