unicorn 1.1.6 → 1.1.7

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.
@@ -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