1
2
3
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
| | # -*- encoding: binary -*-
module Unicorn
# Run GC after every request, after closing the client socket and
# before attempting to accept more connections.
#
# This shouldn't hurt overall performance as long as the server cluster
# is at <50% CPU capacity, and improves the performance of most memory
# intensive requests. This serves to improve _client-visible_
# performance (possibly at the cost of overall performance).
#
# We'll call GC after each request is been written out to the socket, so
# the client never sees the extra GC hit it.
#
# This middleware is _only_ effective for applications that use a lot
# of memory, and will hurt simpler apps/endpoints that can process
# multiple requests before incurring GC.
#
# This middleware is only designed to work with Unicorn, as it harms
# keepalive performance.
#
# Example (in config.ru):
#
# require 'unicorn/oob_gc'
#
# # GC ever two requests that hit /expensive/foo or /more_expensive/foo
# # in your app. By default, this will GC once every 5 requests
# # for all endpoints in your app
# use Unicorn::OobGC, 2, %r{\A/(?:expensive/foo|more_expensive/foo)}
class OobGC < Struct.new(:app, :interval, :path, :nr, :env, :body)
def initialize(app, interval = 5, path = %r{\A/})
super(app, interval, path, interval)
end
def call(env)
status, headers, self.body = app.call(self.env = env)
[ status, headers, self ]
end
def each(&block)
body.each(&block)
end
# in Unicorn, this is closed _after_ the client socket
def close
body.close if body.respond_to?(:close)
if path =~ env['PATH_INFO'] && ((self.nr -= 1) <= 0)
self.nr = interval
self.body = nil
env.clear
GC.start
end
end
end
end
|