class Clockwork::Manager

Attributes

config[R]

Public Class Methods

new() click to toggle source
# File lib/clockwork/manager.rb, line 7
def initialize
  @events = []
  @callbacks = {}
  @config = default_configuration
  @handler = nil
  @mutex = Mutex.new
  @condvar = ConditionVariable.new
  @finish = false
end

Public Instance Methods

configure() { |config| ... } click to toggle source
# File lib/clockwork/manager.rb, line 21
def configure
  yield(config)
  if config[:sleep_timeout] < 1
    config[:logger].warn 'sleep_timeout must be >= 1 second'
  end
end
default_configuration() click to toggle source
# File lib/clockwork/manager.rb, line 28
def default_configuration
  { :sleep_timeout => 1, :logger => Logger.new(STDOUT), :thread => false, :max_threads => 10 }
end
error_handler(&block) click to toggle source
# File lib/clockwork/manager.rb, line 38
def error_handler(&block)
  @error_handler = block if block_given?
  @error_handler
end
every(period, job='unnamed', options={}, &block) click to toggle source
# File lib/clockwork/manager.rb, line 48
def every(period, job='unnamed', options={}, &block)
  if job.is_a?(Hash) and options.empty?
    options = job
    job = "unnamed"
  end
  if options[:at].respond_to?(:each)
    every_with_multiple_times(period, job, options, &block)
  else
    register(period, job, block, options)
  end
end
fire_callbacks(event, *args) click to toggle source
# File lib/clockwork/manager.rb, line 60
def fire_callbacks(event, *args)
  @callbacks[event].nil? || @callbacks[event].all? { |h| h.call(*args) }
end
graceful_shutdown() click to toggle source
# File lib/clockwork/manager.rb, line 102
def graceful_shutdown
  logger.info 'Gracefully shutting down'
  stop_tick_loop
  wait_tick_loop_finishes
  exit(0)
end
handle_error(e) click to toggle source
# File lib/clockwork/manager.rb, line 153
def handle_error(e)
  error_handler.call(e) if error_handler
end
handle_signal(sig) click to toggle source
# File lib/clockwork/manager.rb, line 83
def handle_signal(sig)
  logger.debug "Got #{sig} signal"
  case sig
  when 'INT'
    shutdown
  when 'TERM'
    # Heroku sends TERM signal, and waits 10 seconds before exit
    graceful_shutdown
  when 'HUP'
    graceful_shutdown
  end
end
handler(&block) click to toggle source
# File lib/clockwork/manager.rb, line 32
def handler(&block)
  @handler = block if block_given?
  raise NoHandlerDefined unless @handler
  @handler
end
log(msg) click to toggle source
# File lib/clockwork/manager.rb, line 157
def log(msg)
  config[:logger].info(msg)
end
log_error(e) click to toggle source
# File lib/clockwork/manager.rb, line 149
def log_error(e)
  config[:logger].error(e)
end
logger() click to toggle source
# File lib/clockwork/manager.rb, line 145
def logger
  config[:logger]
end
on(event, options={}, &block) click to toggle source
# File lib/clockwork/manager.rb, line 43
def on(event, options={}, &block)
  raise "Unsupported callback #{event}" unless [:before_tick, :after_tick, :before_run, :after_run].include?(event.to_sym)
  (@callbacks[event.to_sym]||=[]) << block
end
run() click to toggle source
# File lib/clockwork/manager.rb, line 64
def run
  log "Starting clock for #{@events.size} events: [ #{@events.map(&:to_s).join(' ')} ]"

  sig_read, sig_write = IO.pipe

  (%w[INT TERM HUP] & Signal.list.keys).each do |sig|
    trap sig do
      sig_write.puts(sig)
    end
  end

  run_tick_loop

  while io = IO.select([sig_read])
    sig = io.first[0].gets.chomp
    handle_signal(sig)
  end
end
run_tick_loop() click to toggle source
# File lib/clockwork/manager.rb, line 119
def run_tick_loop
  Thread.new do
    @mutex.synchronize do
      until @finish
        tick
        interval = config[:sleep_timeout] - Time.now.subsec + 0.001
        @condvar.wait(@mutex, interval) if interval > 0
      end
    end
  end
end
shutdown() click to toggle source
# File lib/clockwork/manager.rb, line 96
def shutdown
  logger.info 'Shutting down'
  stop_tick_loop
  exit(0)
end
stop_tick_loop() click to toggle source
# File lib/clockwork/manager.rb, line 109
def stop_tick_loop
  @finish = true
end
thread_available?() click to toggle source
# File lib/clockwork/manager.rb, line 17
def thread_available?
  Thread.list.select { |t| t['creator'] == self }.count < config[:max_threads]
end
tick(t=Time.now) click to toggle source
# File lib/clockwork/manager.rb, line 131
def tick(t=Time.now)
  if (fire_callbacks(:before_tick))
    events = events_to_run(t)
    events.each do |event|
      if (fire_callbacks(:before_run, event, t))
        event.run(t)
        fire_callbacks(:after_run, event, t)
      end
    end
  end
  fire_callbacks(:after_tick)
  events
end
wait_tick_loop_finishes() click to toggle source
# File lib/clockwork/manager.rb, line 113
def wait_tick_loop_finishes
  @mutex.synchronize do # wait by synchronize
    @condvar.signal
  end
end

Private Instance Methods

events_to_run(t) click to toggle source
# File lib/clockwork/manager.rb, line 162
def events_to_run(t)
  @events.select{ |event| event.run_now?(t) }
end
every_with_multiple_times(period, job, options={}, &block) click to toggle source
# File lib/clockwork/manager.rb, line 172
def every_with_multiple_times(period, job, options={}, &block)
  each_options = options.clone
  options[:at].each do |at|
    each_options[:at] = at
    register(period, job, block, each_options)
  end
end
register(period, job, block, options) click to toggle source
# File lib/clockwork/manager.rb, line 166
def register(period, job, block, options)
  event = Event.new(self, period, job, block || handler, options)
  @events << event
  event
end