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.
- data/.document +1 -0
- data/Documentation/GNUmakefile +4 -1
- data/Documentation/comparison.css +6 -0
- data/Documentation/comparison.haml +297 -0
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +24 -17
- data/README +32 -28
- data/Summary +7 -0
- data/TODO +4 -6
- data/bin/rainbows +2 -2
- data/lib/rainbows.rb +33 -3
- data/lib/rainbows/actor_spawn.rb +29 -0
- data/lib/rainbows/app_pool.rb +17 -6
- data/lib/rainbows/base.rb +10 -13
- data/lib/rainbows/const.rb +1 -1
- data/lib/rainbows/dev_fd_response.rb +6 -0
- data/lib/rainbows/error.rb +34 -0
- data/lib/rainbows/ev_core.rb +3 -12
- data/lib/rainbows/event_machine.rb +7 -9
- data/lib/rainbows/fiber.rb +15 -0
- data/lib/rainbows/fiber/base.rb +112 -0
- data/lib/rainbows/fiber/io.rb +65 -0
- data/lib/rainbows/fiber/queue.rb +35 -0
- data/lib/rainbows/fiber_pool.rb +44 -0
- data/lib/rainbows/fiber_spawn.rb +34 -0
- data/lib/rainbows/http_server.rb +14 -1
- data/lib/rainbows/never_block.rb +69 -0
- data/lib/rainbows/rev.rb +7 -0
- data/lib/rainbows/rev/client.rb +9 -3
- data/lib/rainbows/rev/core.rb +2 -5
- data/lib/rainbows/rev/heartbeat.rb +5 -1
- data/lib/rainbows/rev_thread_spawn.rb +62 -60
- data/lib/rainbows/revactor.rb +22 -23
- data/lib/rainbows/thread_pool.rb +28 -26
- data/lib/rainbows/thread_spawn.rb +33 -33
- data/local.mk.sample +9 -7
- data/rainbows.gemspec +8 -2
- data/t/GNUmakefile +14 -7
- data/t/fork-sleep.ru +10 -0
- data/t/simple-http_FiberPool.ru +9 -0
- data/t/simple-http_FiberSpawn.ru +9 -0
- data/t/simple-http_NeverBlock.ru +11 -0
- data/t/sleep.ru +2 -0
- data/t/t0000-simple-http.sh +12 -1
- data/t/t0001-unix-http.sh +12 -1
- data/t/t0009-broken-app.sh +56 -0
- data/t/t0009.ru +13 -0
- data/t/t0010-keepalive-timeout-effective.sh +42 -0
- data/t/t0011-close-on-exec-set.sh +54 -0
- data/t/t0300-async_sinatra.sh +1 -1
- data/t/t9000-rack-app-pool.sh +1 -1
- data/t/t9000.ru +8 -5
- data/t/test-lib.sh +14 -4
- metadata +33 -5
- 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
|
data/t/t0300-async_sinatra.sh
CHANGED
data/t/t9000-rack-app-pool.sh
CHANGED
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
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
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 "
|
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.
|
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-
|
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
|
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
|