8

Unicorn has OobGC rack middleware that can be used to run GC.start after a certain number of requests.

Is there a similar sort of thing in Phusion Passenger?

eric
  • 1,168
  • 8
  • 18
  • If you have a memory leak why not deal with it head on? – Devin M Jun 03 '11 at 01:57
  • 1
    It isn't actually a memory leak, it's just that sometimes I have to use a lot of memory. I would rather take the hit of the GC outside of the request/response cycle. – eric Jun 03 '11 at 03:26

3 Answers3

5

Phusion Passenger 4 officially introduces an out of band garbage collection mechanism. It's more flexible than Unicorn's by allowing any arbitrary work, not just garbage collection. http://blog.phusion.nl/2013/01/22/phusion-passenger-4-technology-preview-out-of-band-work/

Hongli
  • 18,682
  • 15
  • 79
  • 107
3

Hooking into PhusionPassenger::Rack::RequestHandler#process_request() is the only mechanism I have found.

To do this in a similar way to the Unicorn OobGC, you can use the following module:

module PassengerOobGC
  def self.install!(path, interval = 5)
    self.const_set :OOBGC_PATH,     path
    self.const_set :OOBGC_INTERVAL, interval
    @@oob_nr = interval
    PhusionPassenger::Rack::RequestHandler.send :include, self
  end

  def self.included(base)
    base.send :alias_method_chain, :process_request, :gc
  end

  def process_request_with_gc(env, *args)
    process_request_without_gc(env, *args)

    if OOBGC_PATH =~ env["PATH_INFO"] && ((@@oob_nr -= 1) <= 0)
      @@oob_nr = OOBGC_INTERVAL
      GC.start
    end
  end
end

and invoke it in an initializer with:

if defined?(PhusionPassenger::Rack::RequestHandler)
  require 'passenger_oob_gc'
  PassengerOobGC.install!(%r{^/admin/}, 3)
end
eric
  • 1,168
  • 8
  • 18
  • After tuning GC environment variables (we're using REE 1.8.7) things are humming along - but when I added this code to do GC outside of req/resp cycle everything slowed down (significantly; 50%+ slower). How did the above code affect performance for you? – Raphael Jun 06 '12 at 21:13
  • Hmm, this also appears to break the New Relic agent. Have you revised this at all? – Raphael Jun 07 '12 at 15:03
  • So, this code just kills my app instance after the request completes and then passenger spawns a new app. Not very performant. Have you watched the PIDs of your app instances when doing this? – Raphael Jun 11 '12 at 21:04
  • 1
    I just tested this by replacing the _GC.start_ with _sleep 10_, and it seems this solution is not correct (anymore) as the sleep delays the request. The answer below by Matthew seems to work on the other hand. – the8472 Jul 20 '12 at 18:33
2

You have to patch Passenger. Doing a GC.start after each request has been handed off ensures that garbage collection never occurs while holding a client request. This is a one-line change that you might consider if you're trying to reduce your average request time.

In lib/phusion_passenger/abstract_request_handler.rb, patch accept_and_process_next_request and add the GC.start call at the end, with an appropriate interval.

See this commit for an example (thanks, @raphaelcm).

Matthew Ratzloff
  • 4,518
  • 1
  • 31
  • 35
  • Do you have a link to the change you're referring to? – eric Sep 09 '11 at 05:40
  • according to this post: http://www.williambharding.com/blog/uncategorized/rails-3-performance-abysmal-to-good-to-great/, you can have rails GC inbetween requests by adding this line of code to Passenger: https://github.com/wbharding/passenger/commit/58dae4baf153de30dbfae5cf0e0c38bc653b366d – Raphael Jun 06 '12 at 21:15
  • Ah, sorry. I never followed up on this post and just saw this update. The patch @raphaelcm posted is in fact what I was alluding to. – Matthew Ratzloff Jun 07 '12 at 22:58