Skip to content

Instantly share code, notes, and snippets.

@exAspArk
Created December 27, 2016 16:12
Show Gist options
  • Save exAspArk/897bd2a284b635645a39c24c30e7c73d to your computer and use it in GitHub Desktop.
Save exAspArk/897bd2a284b635645a39c24c30e7c73d to your computer and use it in GitHub Desktop.
MemoryMiddleware
class MemoryMiddleware
ENV_REQUEST_PATH = 'REQUEST_PATH'.freeze
ENV_PUMA_AFTER_REPLY = 'rack.after_reply'.freeze
LOGGER = Logger.new('/tmp/memory.log'.freeze)
def initialize(app)
@app = app
end
def call(env)
path = env[ENV_REQUEST_PATH]
return @app.call(env) if asset_request?(path)
result = nil
log(path) { result = @app.call(env) }
schedule_gc(env)
result
end
private
def asset_request?(path) # w/o nginx in development env it serves assets as well
path.match(/\.(js|ico|png|gif|css)\z/.freeze)
end
def log(path, &block)
pid = Process.pid
heap_before = GC.stat[:heap_live_slots] / 1_000
usage_before = (Integer(`ps -o rss= -p #{pid}`) * 0.001).to_i
result = block.call
usage_after = (Integer(`ps -o rss= -p #{pid}`) * 0.001).to_i
heap_after = GC.stat[:heap_live_slots] / 1_000
diff_usage = usage_after - usage_before
diff_heap = heap_after - heap_before
msg = "#{diff_usage} mb, #{diff_heap} heap – process [#{pid}] #{path} – #{usage_after} mb, #{heap_after} heap"
LOGGER.info(msg)
result
end
def schedule_gc(env) # in Ruby >= 2.2 GC won't stop the world (incremental)
return if env[ENV_PUMA_AFTER_REPLY].nil?
env[ENV_PUMA_AFTER_REPLY] << -> { GC.start }
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment