diff options
author | Eric Wong <normalperson@yhbt.net> | 2010-05-14 18:27:35 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2010-05-14 18:40:17 +0000 |
commit | 95b75a5043b34f39ece4f52befb4b3f884dfdd20 (patch) | |
tree | 502016acafb35277ca8305b9e0255cad6ba7d9f6 | |
parent | bbefb358174e73d7edbf8a1014817fe1557e39af (diff) | |
download | unicorn-95b75a5043b34f39ece4f52befb4b3f884dfdd20.tar.gz |
This middleware allows configurable out-of-band garbage collection outside of the normal request/response cycle. It offers configurable paths (to only GC on expensive actions) and intervals to limit GC frequency. It is only expected to work well with Unicorn, as it would hurt performance on single-threaded servers if they have keepalive enabled. Obviously this does not work well for multi-threaded or evented servers that serve multiple clients at once.
-rw-r--r-- | lib/unicorn/oob_gc.rb | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/lib/unicorn/oob_gc.rb b/lib/unicorn/oob_gc.rb new file mode 100644 index 0000000..8dc4dcf --- /dev/null +++ b/lib/unicorn/oob_gc.rb @@ -0,0 +1,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 |