class ASF::AutoGC
‘use’ the following class in config.ru to automatically run Garbage Collection every ‘n’ requests, or ‘m’ minutes.
This tries to run garbage collection “out of band” (i.e., between requests), and when other requests are active (which can happen with threaded servers like Puma).
In addition to keeping memory usage bounded, this keeps the LDAP
cache from going stale.
Public Class Methods
Source
# File lib/whimsy/asf/rack.rb, line 106 def initialize(app, frequency=100, minutes=15) @app = app @frequency = frequency @request_count = 0 @queue = Queue.new @mutex = Mutex.new if defined?(PhusionPassenger) # https://github.com/suyccom/yousell/blob/master/config.ru # https://www.phusionpassenger.com/library/indepth/ruby/out_of_band_work.html if PhusionPassenger.respond_to?(:require_passenger_lib) PhusionPassenger.require_passenger_lib 'rack/out_of_band_gc' else # Phusion Passenger < 4.0.33 require 'phusion_passenger/rack/out_of_band_gc' end @passenger = PhusionPassenger::Rack::OutOfBandGc.new(app, frequency) end Thread.kill(@@background) if @@background if minutes # divide minutes by frequency and use the result to determine the # time between simulated requests @@background = Thread.new do seconds = minutes * 60.0 / frequency loop do sleep seconds maybe_perform_gc end end end end
Define the frequency with which GC should be run (as in every ‘n’ requests), and the maximum number of idle minutes between GC runs. This class also will make use of PhusionPassenger’s out of band GC, if available.
Public Instance Methods
Source
# File lib/whimsy/asf/rack.rb, line 146 def call(env) @queue.push 1 if @passenger @passenger.call(env) else # https://github.com/puma/puma/issues/450 status, header, body = @app.call(env) if (ary = env['rack.after_reply']) # this is intended to be assignment, see #108 ary << lambda {maybe_perform_gc} else Thread.new {sleep 0.1; maybe_perform_gc} end [status, header, body] end ensure @queue.pop end
Rack middleware used to push an object onto the queue prior to the request (this stops AutoGC
from running during the request), and popping it afterward the request completes. Also will spin off a thread to run GC after the reply completes (using rack.after_reply if available), otherwise using a standard Thread.
Source
# File lib/whimsy/asf/rack.rb, line 169 def maybe_perform_gc @mutex.synchronize do @request_count += 1 if @queue.empty? and @request_count >= @frequency @request_count = 0 disabled = GC.enable GC.start GC.disable if disabled end end end
Run GC when no requests are active and after every @frequency
events.