class PeriodicScheduler
Public Class Methods
new(quantum = 5.0, options = {})
click to toggle source
# File lib/periodic-scheduler.rb, line 82 def initialize(quantum = 5.0, options = {}) time_source = (options[:time_source] or lambda {Time.now.to_f}) wait_function = (options[:wait_function] or lambda{|t| sleep t}) @quantized_space = RealTimeToQuantizedSpaceProjection.new( quantum, lambda {|v| v.ceil} # behave like sleep - never execute too early ) @time_source = time_source @wait_function = wait_function @events = {} end
Public Instance Methods
after(period, &callback)
click to toggle source
# File lib/periodic-scheduler.rb, line 96 def after(period, &callback) schedule_event Event.new(@quantized_space, real_now, period, false, &callback) end
empty?()
click to toggle source
# File lib/periodic-scheduler.rb, line 156 def empty? @events.empty? end
every(period, &callback)
click to toggle source
# File lib/periodic-scheduler.rb, line 100 def every(period, &callback) schedule_event Event.new(@quantized_space, real_now, period, true, &callback) end
run() { |error| ... }
click to toggle source
# File lib/periodic-scheduler.rb, line 113 def run earliest_quant = @events.keys.sort.first raise EmptyScheduleError, "no events scheduled" unless earliest_quant wait_time = @quantized_space.revers_project(earliest_quant) - real_now wait_time = 0 if wait_time < 0 wait(wait_time) objects = [] qnow = quantized_now # move quants to be run away to separate array quants = @events.keys.select{|k| k <= qnow}.sort.map{|q| @events.delete(q)} # we have missed one or more scheduled quants if quants.length > 1 begin # we raise it so it has proper backtrace raise MissedScheduleError.new("missed schedule by #{-wait_time} seconds") rescue StandardError => error yield error if block_given? end end # Call callback for every quant and reschedule if needed quants.each do |events| # get all events for quantum that are not stopped events.each do |e| begin objects << e.call rescue StandardError => error # Yield errors to block yield error if block_given? end e.reschedule(quantized_now) if e.keep? and not e.stopped? end end # return collected callabck return objects objects end
run!(&block)
click to toggle source
# File lib/periodic-scheduler.rb, line 104 def run!(&block) begin loop do run(&block) end rescue EmptyScheduleError end end
Private Instance Methods
quantized_now()
click to toggle source
# File lib/periodic-scheduler.rb, line 193 def quantized_now @quantized_space.project(real_now) end
real_now()
click to toggle source
# File lib/periodic-scheduler.rb, line 189 def real_now @time_source.call end
schedule_event(event)
click to toggle source
# File lib/periodic-scheduler.rb, line 162 def schedule_event(event) quant = event.quantum_period (@events[quant] ||= []) << event event.reschedule_hook do |event| unschedule_event(event, quant) schedule_event(event) end event.stop_hook do |event| unschedule_event(event, quant) end event end
unschedule_event(event, quant)
click to toggle source
# File lib/periodic-scheduler.rb, line 178 def unschedule_event(event, quant) return unless @events[quant] @events[quant].delete(event) @events.delete(quant) if @events[quant].empty? end
wait(time)
click to toggle source
# File lib/periodic-scheduler.rb, line 184 def wait(time) fail "time must be a positive number" if time < 0 @wait_function.call(time) end