Class: Tickwork::Manager

Inherits:
Object
  • Object
show all
Defined in:
lib/tickwork/manager.rb

Defined Under Namespace

Classes: DuplicateJobName, NoDataStoreDefined, NoHandlerDefined

Constant Summary collapse

MANAGER_KEY =
'__manager'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeManager



11
12
13
14
15
16
17
# File 'lib/tickwork/manager.rb', line 11

def initialize
  @events = []
  @callbacks = {}
  @config = default_configuration
  @handler = nil
  @error_handler = nil
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



9
10
11
# File 'lib/tickwork/manager.rb', line 9

def config
  @config
end

Instance Method Details

#clear!Object



131
132
133
# File 'lib/tickwork/manager.rb', line 131

def clear!
  data_store.write(data_store_key, nil)
end

#configure {|config| ... } ⇒ Object

Yields:



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/tickwork/manager.rb', line 23

def configure
  yield(config)
  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_storeObject



62
63
64
# File 'lib/tickwork/manager.rb', line 62

def data_store
  config[:data_store]
end

#data_store_keyObject



86
87
88
# File 'lib/tickwork/manager.rb', line 86

def data_store_key
  @data_store_key ||= config[:namespace] + MANAGER_KEY
end

#default_configurationObject



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/tickwork/manager.rb', line 39

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) ⇒ Object



57
58
59
60
# File 'lib/tickwork/manager.rb', line 57

def error_handler(&block)
  @error_handler = block if block_given?
  @error_handler
end

#every(period, job, options = {}, &block) ⇒ Object



71
72
73
74
75
76
77
78
79
80
# File 'lib/tickwork/manager.rb', line 71

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) ⇒ Object



82
83
84
# File 'lib/tickwork/manager.rb', line 82

def fire_callbacks(event, *args)
  @callbacks[event].nil? || @callbacks[event].all? { |h| h.call(*args) }
end

#handle_error(e) ⇒ Object



139
140
141
# File 'lib/tickwork/manager.rb', line 139

def handle_error(e)
  error_handler.call(e) if error_handler
end

#handler(&block) ⇒ Object

Raises:



51
52
53
54
55
# File 'lib/tickwork/manager.rb', line 51

def handler(&block)
  @handler = block if block_given?
  raise NoHandlerDefined unless @handler
  @handler
end

#log(msg) ⇒ Object



143
144
145
# File 'lib/tickwork/manager.rb', line 143

def log(msg)
  config[:logger].info(msg)
end

#log_error(e) ⇒ Object



135
136
137
# File 'lib/tickwork/manager.rb', line 135

def log_error(e)
  config[:logger].error(e)
end

#on(event, options = {}, &block) ⇒ Object



66
67
68
69
# File 'lib/tickwork/manager.rb', line 66

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

#runObject

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

Raises:



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/tickwork/manager.rb', line 93

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?Boolean



19
20
21
# 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) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/tickwork/manager.rb', line 116

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