module UnicornWrangler
Read RSS based on the OS we are in. When in linux, we can read the proc status file and parse out the RSS which is much faster than forking+execing ps.
Constants
- STATS_NAMESPACE
- VERSION
Attributes
handlers[R]
request_time[R]
requests[R]
sending_myself_term[RW]
Public Class Methods
kill_worker()
click to toggle source
# File lib/unicorn_wrangler.rb, line 60 def kill_worker self.sending_myself_term = true # no need to clean up since we are dead after Process.kill(:TERM, Process.pid) end
perform_hook(name)
click to toggle source
# File lib/unicorn_wrangler.rb, line 77 def perform_hook(name) if hook = @hooks[name] hook.call end end
perform_request() { || ... }
click to toggle source
called from the unicorn server after each request
# File lib/unicorn_wrangler.rb, line 66 def perform_request returned = nil @requests ||= 0 @requests += 1 @request_time ||= 0 @request_time += Benchmark.realtime { returned = yield } returned ensure @handlers.each { |handler| handler.call(@requests, @request_time) } end
setup( kill_after_requests: 10000, gc_after_request_time: 10, kill_on_too_much_memory: {}, map_term_to_quit: false, logger:, stats: nil )
click to toggle source
called from unicorn config (usually config/unicorn.rb) high level interface to keep setup consistent / simple set values to false to disable
# File lib/unicorn_wrangler.rb, line 18 def setup( kill_after_requests: 10000, gc_after_request_time: 10, kill_on_too_much_memory: {}, map_term_to_quit: false, logger:, stats: nil # provide a statsd client with your apps namespace to collect stats ) logger.info "Sending stats to under #{stats.namespace}.#{STATS_NAMESPACE}" if stats @handlers = [] @handlers << RequestKiller.new(logger, stats, kill_after_requests) if kill_after_requests @handlers << OutOfMemoryKiller.new(logger, stats, kill_on_too_much_memory) if kill_on_too_much_memory @handlers << OutOfBandGC.new(logger, stats, gc_after_request_time) if gc_after_request_time @hooks = {} if map_term_to_quit # - on heroku & kubernetes all processes get TERM, so we need to trap in master and worker # - trapping has to be done in the before_fork since unicorn sets up it's own traps on start # - we cannot write to logger inside of a trap, so need to spawn a new Thread # - manual test: add a slow route + rails s + curl + pkill -TERM -f 'unicorn master' - request finished? @hooks[:before_fork] = -> do Signal.trap :TERM do Thread.new { logger.info 'master intercepting TERM and sending myself QUIT instead' } Process.kill :QUIT, Process.pid end end @hooks[:after_fork] = ->(*) do # Signal.trap returns the trap that unicorn set, which is an exit!(0) and calls that when sending myself term previous_trap = Signal.trap :TERM do if sending_myself_term previous_trap.call else Thread.new { logger.info 'worker intercepting TERM and doing nothing. Wait for master to send QUIT' } end end end end Unicorn::HttpServer.prepend UnicornExtension end