module NdrDevSupport::Daemon::Stoppable

Behaviour that allows daemons to be restarted, and stopped by god. To use, you need to call `super` in the initialize method, if defined.

Constants

BIG_SLEEP

how long the daemon waits when it runs out of things to do:

LITTLE_SLEEP

when idle, how long the daemon between making restart checks?

MAX_MEMORY
MAX_UPTIME
RESTART_FILENAME

touch this file to trigger graceful exit

Public Class Methods

new(*) click to toggle source
# File lib/ndr_dev_support/daemon/stoppable.rb, line 29
def initialize(*)
  setup_signals

  @start_time = Time.current
end

Public Instance Methods

log(message, level = :info) click to toggle source
# File lib/ndr_dev_support/daemon/stoppable.rb, line 70
def log(message, level = :info)
  tags    = "[#{Time.current.to_s(:db)}] [#{level.upcase}] [daemon: #{name} (#{Process.pid})]"
  message = "#{tags} #{message}"

  logger.send(level, message)
end
logger() click to toggle source
# File lib/ndr_dev_support/daemon/stoppable.rb, line 66
def logger
  @logger ||= defined?(Rails) && Rails.logger ? Rails.logger : Logger.new($stdout)
end
run(exit_when_done: false) click to toggle source
# File lib/ndr_dev_support/daemon/stoppable.rb, line 43
def run(exit_when_done: false)
  loop do
    run_once

    # we've done all we can for the time being; either exit now, or
    # have a sleep and loop round for another go:
    break if exit_when_done
    snooze(BIG_SLEEP)
    # Our snooze may have come to an abrupt end:
    break if should_stop?
  end

  if should_stop?
    # An instruction to stop has been received:
    log('Stopping')
    return :stopped
  else
    # Processing has come to a natural end:
    log('Done, exiting')
    return :exiting
  end
end
should_stop?() click to toggle source
# File lib/ndr_dev_support/daemon/stoppable.rb, line 39
def should_stop?
  @should_stop ||= restart_file_touched? || excessive_memory? || been_up_a_while?
end
stop() click to toggle source
# File lib/ndr_dev_support/daemon/stoppable.rb, line 35
def stop
  @should_stop = true
end

Private Instance Methods

been_up_a_while?() click to toggle source
# File lib/ndr_dev_support/daemon/stoppable.rb, line 93
def been_up_a_while?
  start_time < MAX_UPTIME.ago
end
excessive_memory?() click to toggle source
# File lib/ndr_dev_support/daemon/stoppable.rb, line 87
def excessive_memory?
  (`ps -o rss= -p #{$$}`.to_i.kilobytes) > MAX_MEMORY
rescue
  false
end
restart_file_touched?() click to toggle source
# File lib/ndr_dev_support/daemon/stoppable.rb, line 83
def restart_file_touched?
  File.exist?(RESTART_FILENAME) && File.mtime(RESTART_FILENAME) > start_time
end
setup_signals() click to toggle source
# File lib/ndr_dev_support/daemon/stoppable.rb, line 79
def setup_signals
  Signal.trap('TERM') { stop }
end
snooze(duration) click to toggle source

sleeps for `duration`, but wakes up periodically to see if the daemon has been asked to restart. If so, returns immediately.

# File lib/ndr_dev_support/daemon/stoppable.rb, line 100
def snooze(duration)
  number_of_mini_sleeps = duration / LITTLE_SLEEP
  initial_sleep_length  = duration % LITTLE_SLEEP

  sleep(initial_sleep_length)

  number_of_mini_sleeps.times do
    return if should_stop?
    sleep(LITTLE_SLEEP)
  end
end