class Tickwork::Manager

Constants

MANAGER_KEY

Attributes

config[R]

Public Class Methods

new() click to toggle source
# File lib/tickwork/manager.rb, line 11
def initialize
  @events = []
  @callbacks = {}
  @config = default_configuration
  @handler = nil
  @error_handler = nil
end

Public Instance Methods

clear!() click to toggle source
# File lib/tickwork/manager.rb, line 134
def clear!
  data_store.write(data_store_key, nil)
end
configure() { |config| ... } click to toggle source
# File lib/tickwork/manager.rb, line 23
def configure
  yield(config)
  [:max_threads, :tick_size, :max_ticks, :max_catchup].each do |int_config_key|
    config[int_config_key] = config[int_config_key].to_i
  end
  if config[:sleep_timeout]
    config[:logger].warn 'INCORRECT USAGE: sleep_timeout is not used'
    if config[:sleep_timeout] < 1
      config[:logger].warn 'sleep_timeout must be >= 1 second'
    end
  end
  if config[:data_store].nil?
    raise NoDataStoreDefined.new
  end
  if config[:tick_size] > 60
    config[:logger].warn 'tick_size is greater than 60. Events scheduled for a specific time may be missed'
  end
end
data_store() click to toggle source
# File lib/tickwork/manager.rb, line 65
def data_store
  config[:data_store]
end
data_store_key() click to toggle source
# File lib/tickwork/manager.rb, line 89
def data_store_key
  @data_store_key ||= config[:namespace] + MANAGER_KEY
end
default_configuration() click to toggle source
# File lib/tickwork/manager.rb, line 42
def default_configuration
  { 
    logger: Logger.new(STDOUT), 
    thread: false, 
    max_threads: 10,
    namespace: '_tickwork_',
    tick_size: 60, # 1 minute
    max_ticks: 10,
    max_catchup: 3600 # 1 hour
  }
end
error_handler(&block) click to toggle source
# File lib/tickwork/manager.rb, line 60
def error_handler(&block)
  @error_handler = block if block_given?
  @error_handler
end
every(period, job, options={}, &block) click to toggle source
# File lib/tickwork/manager.rb, line 74
def every(period, job, options={}, &block)
  if period < config[:tick_size]
    config[:logger].warn 'period is smaller than tick size. will fail to schedule all events'
  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/tickwork/manager.rb, line 85
def fire_callbacks(event, *args)
  @callbacks[event].nil? || @callbacks[event].all? { |h| h.call(*args) }
end
handle_error(e) click to toggle source
# File lib/tickwork/manager.rb, line 142
def handle_error(e)
  error_handler.call(e) if error_handler
end
handler(&block) click to toggle source
# File lib/tickwork/manager.rb, line 54
def handler(&block)
  @handler = block if block_given?
  raise NoHandlerDefined unless @handler
  @handler
end
log(msg) click to toggle source
# File lib/tickwork/manager.rb, line 146
def log(msg)
  config[:logger].info(msg)
end
log_error(e) click to toggle source
# File lib/tickwork/manager.rb, line 138
def log_error(e)
  config[:logger].error(e)
end
on(event, options={}, &block) click to toggle source
# File lib/tickwork/manager.rb, line 69
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

pretty straight forward if you think about it run the ticks from the last time we ran to our max but don't run ticks in the future

# File lib/tickwork/manager.rb, line 96
def run
  raise NoDataStoreDefined.new if data_store.nil?
  log "Starting clock for #{@events.size} events: [ #{@events.map(&:to_s).join(' ')} ]"

  last = last_t = data_store.read(data_store_key)
  last ||= Time.now.to_i - config[:tick_size] 
  if !config[:max_catchup].nil? && config[:max_catchup] > 0 && last < Time.now.to_i - config[:max_catchup]
    last = Time.now.to_i - config[:max_catchup] - config[:tick_size]
  end

  ticks = 0
  tick_time = last + config[:tick_size]

  while ticks < config[:max_ticks] && tick_time <= Time.now.to_i do
    tick(tick_time) 
    last = tick_time
    tick_time += config[:tick_size]
    ticks += 1
  end
  data_store.write(data_store_key, last)
  last
end
thread_available?() click to toggle source
# File lib/tickwork/manager.rb, line 19
def thread_available?
  Thread.list.select { |t| t['creator'] == self }.count < config[:max_threads]
end
tick(t=Time.now.to_i) click to toggle source
# File lib/tickwork/manager.rb, line 119
def tick(t=Time.now.to_i)
  t = Time.at(t) # TODO refactor below
  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

Private Instance Methods

events_to_run(t) click to toggle source
# File lib/tickwork/manager.rb, line 151
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/tickwork/manager.rb, line 169
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 + '_' + at, block, each_options)
  end
end
guard_duplicate_events(event) click to toggle source
# File lib/tickwork/manager.rb, line 163
def guard_duplicate_events(event)
  if @events.map{|e| e.to_s }.include? event.to_s
    raise DuplicateJobName
  end
end
register(period, job, block, options) click to toggle source
# File lib/tickwork/manager.rb, line 155
def register(period, job, block, options)
  options.merge({:namespace => config[:namespace]})
  event = Event.new(self, period, job, block || handler, options)
  guard_duplicate_events(event)
  @events << event
  event
end