unicorn 1.1.6 → 1.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v1.1.6.GIT
4
+ DEF_VER=v1.1.7.GIT
5
5
 
6
6
  LF='
7
7
  '
@@ -1,33 +1,2 @@
1
- # Run GC after every request, before attempting to accept more connections.
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
@@ -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
- [ 200, headers, out ]
118
+ [ status, headers, out ]
118
119
  end
119
120
 
120
121
  # ensures rack.input is a file handle that we can redirect stdin to
@@ -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.6
12
- UNICORN_VERSION="1.1.6"
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
@@ -1,58 +1,69 @@
1
1
  # -*- encoding: binary -*-
2
- module Unicorn
3
2
 
4
- # Run GC after every request, after closing the client socket and
5
- # before attempting to accept more connections.
6
- #
7
- # This shouldn't hurt overall performance as long as the server cluster
8
- # is at <50% CPU capacity, and improves the performance of most memory
9
- # intensive requests. This serves to improve _client-visible_
10
- # performance (possibly at the cost of overall performance).
11
- #
12
- # We'll call GC after each request is been written out to the socket, so
13
- # the client never sees the extra GC hit it.
14
- #
15
- # This middleware is _only_ effective for applications that use a lot
16
- # of memory, and will hurt simpler apps/endpoints that can process
17
- # multiple requests before incurring GC.
18
- #
19
- # This middleware is only designed to work with Unicorn, as it harms
20
- # keepalive performance.
21
- #
22
- # Example (in config.ru):
23
- #
24
- # require 'unicorn/oob_gc'
25
- #
26
- # # GC ever two requests that hit /expensive/foo or /more_expensive/foo
27
- # # in your app. By default, this will GC once every 5 requests
28
- # # for all endpoints in your app
29
- # use Unicorn::OobGC, 2, %r{\A/(?:expensive/foo|more_expensive/foo)}
30
- class OobGC < Struct.new(:app, :interval, :path, :nr, :env, :body)
31
-
32
- def initialize(app, interval = 5, path = %r{\A/})
33
- super(app, interval, path, interval)
34
- end
35
-
36
- def call(env)
37
- status, headers, self.body = app.call(self.env = env)
38
- [ status, headers, self ]
39
- end
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
- def each(&block)
42
- body.each(&block)
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
- # in Unicorn, this is closed _after_ the client socket
46
- def close
47
- body.close if body.respond_to?(:close)
48
-
49
- if path =~ env['PATH_INFO'] && ((self.nr -= 1) <= 0)
50
- self.nr = interval
51
- self.body = nil
52
- env.clear
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
@@ -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
+ }
@@ -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
+ }
@@ -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: 31
5
- prerelease: false
4
+ hash: 29
5
+ prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 1
9
- - 6
10
- version: 1.1.6
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-01-07 00:00:00 +00:00
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.3.7
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