unicorn 1.1.6 → 1.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/GIT-VERSION-GEN +1 -1
- data/examples/big_app_gc.rb +2 -33
- data/lib/unicorn/app/exec_cgi.rb +2 -1
- data/lib/unicorn/const.rb +2 -2
- data/lib/unicorn/oob_gc.rb +61 -50
- data/t/oob_gc.ru +21 -0
- data/t/oob_gc_path.ru +21 -0
- data/t/t9001-oob_gc.sh +47 -0
- data/t/t9002-oob_gc-path.sh +75 -0
- metadata +10 -8
data/GIT-VERSION-GEN
CHANGED
data/examples/big_app_gc.rb
CHANGED
@@ -1,33 +1,2 @@
|
|
1
|
-
#
|
2
|
-
#
|
3
|
-
# You could customize this patch to read REQ["PATH_INFO"] and only
|
4
|
-
# call GC.start after expensive requests.
|
5
|
-
#
|
6
|
-
# We could have this wrap the response body.close as middleware, but the
|
7
|
-
# scannable stack is would still be bigger than it would be here.
|
8
|
-
#
|
9
|
-
# This shouldn't hurt overall performance as long as the server cluster
|
10
|
-
# is at <=50% CPU capacity, and improves the performance of most memory
|
11
|
-
# intensive requests. This serves to improve _client-visible_
|
12
|
-
# performance (possibly at the cost of overall performance).
|
13
|
-
#
|
14
|
-
# We'll call GC after each request is been written out to the socket, so
|
15
|
-
# the client never sees the extra GC hit it. It's ideal to call the GC
|
16
|
-
# inside the HTTP server (vs middleware or hooks) since the stack is
|
17
|
-
# smaller at this point, so the GC will both be faster and more
|
18
|
-
# effective at releasing unused memory.
|
19
|
-
#
|
20
|
-
# This monkey patch is _only_ effective for applications that use a lot
|
21
|
-
# of memory, and will hurt simpler apps/endpoints that can process
|
22
|
-
# multiple requests before incurring GC.
|
23
|
-
|
24
|
-
class Unicorn::HttpServer
|
25
|
-
REQ = Unicorn::HttpRequest::REQ
|
26
|
-
alias _process_client process_client
|
27
|
-
undef_method :process_client
|
28
|
-
def process_client(client)
|
29
|
-
_process_client(client)
|
30
|
-
REQ.clear
|
31
|
-
GC.start
|
32
|
-
end
|
33
|
-
end if defined?(Unicorn)
|
1
|
+
# see {Unicorn::OobGC}[http://unicorn.bogomips.org/Unicorn/OobGC.html]
|
2
|
+
# Unicorn::OobGC was broken in Unicorn v3.3.1 - v3.6.1 and fixed in v3.6.2
|
data/lib/unicorn/app/exec_cgi.rb
CHANGED
@@ -113,8 +113,9 @@ module Unicorn::App
|
|
113
113
|
when /^[ \t]/ then headers[prev] << "\n#{line}" if prev
|
114
114
|
end
|
115
115
|
end
|
116
|
+
status = headers.delete("Status") || 200
|
116
117
|
headers['Content-Length'] = size.to_s
|
117
|
-
[
|
118
|
+
[ status, headers, out ]
|
118
119
|
end
|
119
120
|
|
120
121
|
# ensures rack.input is a file handle that we can redirect stdin to
|
data/lib/unicorn/const.rb
CHANGED
@@ -8,8 +8,8 @@ module Unicorn
|
|
8
8
|
# Symbols did not really improve things much compared to constants.
|
9
9
|
module Const
|
10
10
|
|
11
|
-
# The current version of Unicorn, currently 1.1.
|
12
|
-
UNICORN_VERSION="1.1.
|
11
|
+
# The current version of Unicorn, currently 1.1.7
|
12
|
+
UNICORN_VERSION="1.1.7"
|
13
13
|
|
14
14
|
DEFAULT_HOST = "0.0.0.0" # default TCP listen host address
|
15
15
|
DEFAULT_PORT = 8080 # default TCP listen port
|
data/lib/unicorn/oob_gc.rb
CHANGED
@@ -1,58 +1,69 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
-
module Unicorn
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
3
|
+
# Runs GC after requests, after closing the client socket and
|
4
|
+
# before attempting to accept more connections.
|
5
|
+
#
|
6
|
+
# This shouldn't hurt overall performance as long as the server cluster
|
7
|
+
# is at <50% CPU capacity, and improves the performance of most memory
|
8
|
+
# intensive requests. This serves to improve _client-visible_
|
9
|
+
# performance (possibly at the cost of overall performance).
|
10
|
+
#
|
11
|
+
# Increasing the number of +worker_processes+ may be necessary to
|
12
|
+
# improve average client response times because some of your workers
|
13
|
+
# will be busy doing GC and unable to service clients. Think of
|
14
|
+
# using more workers with this module as a poor man's concurrent GC.
|
15
|
+
#
|
16
|
+
# We'll call GC after each request is been written out to the socket, so
|
17
|
+
# the client never sees the extra GC hit it.
|
18
|
+
#
|
19
|
+
# This middleware is _only_ effective for applications that use a lot
|
20
|
+
# of memory, and will hurt simpler apps/endpoints that can process
|
21
|
+
# multiple requests before incurring GC.
|
22
|
+
#
|
23
|
+
# This middleware is only designed to work with unicorn, as it harms
|
24
|
+
# performance with keepalive-enabled servers.
|
25
|
+
#
|
26
|
+
# Example (in config.ru):
|
27
|
+
#
|
28
|
+
# require 'unicorn/oob_gc'
|
29
|
+
#
|
30
|
+
# # GC ever two requests that hit /expensive/foo or /more_expensive/foo
|
31
|
+
# # in your app. By default, this will GC once every 5 requests
|
32
|
+
# # for all endpoints in your app
|
33
|
+
# use Unicorn::OobGC, 2, %r{\A/(?:expensive/foo|more_expensive/foo)}
|
34
|
+
#
|
35
|
+
# Feedback from users of early implementations of this module:
|
36
|
+
# * http://comments.gmane.org/gmane.comp.lang.ruby.unicorn.general/486
|
37
|
+
# * http://article.gmane.org/gmane.comp.lang.ruby.unicorn.general/596
|
38
|
+
module Unicorn::OobGC
|
40
39
|
|
41
|
-
|
42
|
-
|
40
|
+
# this pretends to be Rack middleware because it used to be
|
41
|
+
# But we need to hook into unicorn internals so we need to close
|
42
|
+
# the socket before clearing the request env.
|
43
|
+
#
|
44
|
+
# +interval+ is the number of requests matching the +path+ regular
|
45
|
+
# expression before invoking GC.
|
46
|
+
def self.new(app, interval = 5, path = %r{\A/})
|
47
|
+
@@nr = interval
|
48
|
+
self.const_set :OOBGC_PATH, path
|
49
|
+
self.const_set :OOBGC_INTERVAL, interval
|
50
|
+
self.const_set :OOBGC_ENV, Unicorn::HttpRequest::REQ
|
51
|
+
ObjectSpace.each_object(Unicorn::HttpServer) do |s|
|
52
|
+
s.extend(self)
|
43
53
|
end
|
54
|
+
app # pretend to be Rack middleware since it was in the past
|
55
|
+
end
|
44
56
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
GC.start
|
54
|
-
end
|
57
|
+
#:stopdoc:
|
58
|
+
PATH_INFO = "PATH_INFO"
|
59
|
+
def process_client(client)
|
60
|
+
super(client) # Unicorn::HttpServer#process_client
|
61
|
+
if OOBGC_PATH =~ OOBGC_ENV[PATH_INFO] && ((@@nr -= 1) <= 0)
|
62
|
+
@@nr = OOBGC_INTERVAL
|
63
|
+
OOBGC_ENV.clear
|
64
|
+
GC.start
|
55
65
|
end
|
56
|
-
|
57
66
|
end
|
67
|
+
|
68
|
+
# :startdoc:
|
58
69
|
end
|
data/t/oob_gc.ru
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#\-E none
|
2
|
+
require 'unicorn/oob_gc'
|
3
|
+
use Rack::ContentLength
|
4
|
+
use Rack::ContentType, "text/plain"
|
5
|
+
use Unicorn::OobGC
|
6
|
+
$gc_started = false
|
7
|
+
|
8
|
+
# Mock GC.start
|
9
|
+
def GC.start
|
10
|
+
ObjectSpace.each_object(BasicSocket) do |x|
|
11
|
+
next if Unicorn::HttpServer::LISTENERS.include?(x)
|
12
|
+
x.closed? or abort "not closed #{x}"
|
13
|
+
end
|
14
|
+
$gc_started = true
|
15
|
+
end
|
16
|
+
run lambda { |env|
|
17
|
+
if "/gc_reset" == env["PATH_INFO"] && "POST" == env["REQUEST_METHOD"]
|
18
|
+
$gc_started = false
|
19
|
+
end
|
20
|
+
[ 200, {}, [ "#$gc_started\n" ] ]
|
21
|
+
}
|
data/t/oob_gc_path.ru
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#\-E none
|
2
|
+
require 'unicorn/oob_gc'
|
3
|
+
use Rack::ContentLength
|
4
|
+
use Rack::ContentType, "text/plain"
|
5
|
+
use Unicorn::OobGC, 5, /BAD/
|
6
|
+
$gc_started = false
|
7
|
+
|
8
|
+
# Mock GC.start
|
9
|
+
def GC.start
|
10
|
+
ObjectSpace.each_object(BasicSocket) do |x|
|
11
|
+
next if Unicorn::HttpServer::LISTENERS.include?(x)
|
12
|
+
x.closed? or abort "not closed #{x}"
|
13
|
+
end
|
14
|
+
$gc_started = true
|
15
|
+
end
|
16
|
+
run lambda { |env|
|
17
|
+
if "/gc_reset" == env["PATH_INFO"] && "POST" == env["REQUEST_METHOD"]
|
18
|
+
$gc_started = false
|
19
|
+
end
|
20
|
+
[ 200, {}, [ "#$gc_started\n" ] ]
|
21
|
+
}
|
data/t/t9001-oob_gc.sh
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 9 "OobGC test"
|
4
|
+
|
5
|
+
t_begin "setup and start" && {
|
6
|
+
unicorn_setup
|
7
|
+
unicorn -D -c $unicorn_config oob_gc.ru
|
8
|
+
unicorn_wait_start
|
9
|
+
}
|
10
|
+
|
11
|
+
t_begin "test default interval (4 requests)" && {
|
12
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
13
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
14
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
15
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
16
|
+
}
|
17
|
+
|
18
|
+
t_begin "GC starting-request returns immediately" && {
|
19
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
20
|
+
}
|
21
|
+
|
22
|
+
t_begin "GC is started after 5 requests" && {
|
23
|
+
test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
24
|
+
}
|
25
|
+
|
26
|
+
t_begin "reset GC" && {
|
27
|
+
test xfalse = x$(curl -vsSf -X POST http://$listen/gc_reset 2>> $tmp)
|
28
|
+
}
|
29
|
+
|
30
|
+
t_begin "test default interval again (3 requests)" && {
|
31
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
32
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
33
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
34
|
+
}
|
35
|
+
|
36
|
+
t_begin "GC is started after 5 requests" && {
|
37
|
+
test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
38
|
+
}
|
39
|
+
|
40
|
+
t_begin "killing succeeds" && {
|
41
|
+
kill -QUIT $unicorn_pid
|
42
|
+
}
|
43
|
+
|
44
|
+
t_begin "check_stderr" && check_stderr
|
45
|
+
dbgcat r_err
|
46
|
+
|
47
|
+
t_done
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 12 "OobGC test with limited path"
|
4
|
+
|
5
|
+
t_begin "setup and start" && {
|
6
|
+
unicorn_setup
|
7
|
+
unicorn -D -c $unicorn_config oob_gc_path.ru
|
8
|
+
unicorn_wait_start
|
9
|
+
}
|
10
|
+
|
11
|
+
t_begin "test default is noop" && {
|
12
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
13
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
14
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
15
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
16
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
17
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
18
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
19
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
20
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
21
|
+
}
|
22
|
+
|
23
|
+
t_begin "4 bad requests to bump counter" && {
|
24
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
25
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
26
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
27
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
28
|
+
}
|
29
|
+
|
30
|
+
t_begin "GC-starting request returns immediately" && {
|
31
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
32
|
+
}
|
33
|
+
|
34
|
+
t_begin "GC was started after 5 requests" && {
|
35
|
+
test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
36
|
+
}
|
37
|
+
|
38
|
+
t_begin "reset GC" && {
|
39
|
+
test xfalse = x$(curl -vsSf -X POST http://$listen/gc_reset 2>> $tmp)
|
40
|
+
}
|
41
|
+
|
42
|
+
t_begin "test default is noop" && {
|
43
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
44
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
45
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
46
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
47
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
48
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
49
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
50
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
51
|
+
test xfalse = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
52
|
+
}
|
53
|
+
|
54
|
+
t_begin "4 bad requests to bump counter" && {
|
55
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
56
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
57
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
58
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
59
|
+
}
|
60
|
+
|
61
|
+
t_begin "GC-starting request returns immediately" && {
|
62
|
+
test xfalse = x$(curl -vsSf http://$listen/BAD 2>> $tmp)
|
63
|
+
}
|
64
|
+
|
65
|
+
t_begin "GC was started after 5 requests" && {
|
66
|
+
test xtrue = x$(curl -vsSf http://$listen/ 2>> $tmp)
|
67
|
+
}
|
68
|
+
|
69
|
+
t_begin "killing succeeds" && {
|
70
|
+
kill -QUIT $unicorn_pid
|
71
|
+
}
|
72
|
+
|
73
|
+
t_begin "check_stderr" && check_stderr
|
74
|
+
|
75
|
+
t_done
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 1.1.
|
9
|
+
- 7
|
10
|
+
version: 1.1.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Unicorn hackers
|
@@ -15,8 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
19
|
-
default_executable:
|
18
|
+
date: 2011-04-30 00:00:00 Z
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
21
|
name: rack
|
@@ -169,6 +168,8 @@ files:
|
|
169
168
|
- t/bin/utee
|
170
169
|
- t/env.ru
|
171
170
|
- t/my-tap-lib.sh
|
171
|
+
- t/oob_gc.ru
|
172
|
+
- t/oob_gc_path.ru
|
172
173
|
- t/pid.ru
|
173
174
|
- t/rails3-app/.gitignore
|
174
175
|
- t/rails3-app/Gemfile
|
@@ -220,6 +221,8 @@ files:
|
|
220
221
|
- t/t0302-rails3-alt-working_directory.sh
|
221
222
|
- t/t0303-rails3-alt-working_directory_config.ru.sh
|
222
223
|
- t/t0304-rails3-alt-working_directory_no_embed_cli.sh
|
224
|
+
- t/t9001-oob_gc.sh
|
225
|
+
- t/t9002-oob_gc-path.sh
|
223
226
|
- t/test-lib.sh
|
224
227
|
- t/test-rails3.sh
|
225
228
|
- t/write-on-close.ru
|
@@ -318,7 +321,6 @@ files:
|
|
318
321
|
- test/unit/test_upload.rb
|
319
322
|
- test/unit/test_util.rb
|
320
323
|
- unicorn.gemspec
|
321
|
-
has_rdoc: true
|
322
324
|
homepage: http://unicorn.bogomips.org/
|
323
325
|
licenses: []
|
324
326
|
|
@@ -350,7 +352,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
350
352
|
requirements: []
|
351
353
|
|
352
354
|
rubyforge_project: mongrel
|
353
|
-
rubygems_version: 1.
|
355
|
+
rubygems_version: 1.7.2
|
354
356
|
signing_key:
|
355
357
|
specification_version: 3
|
356
358
|
summary: Rack HTTP server for fast clients and Unix
|