class GxG::Events::EventDispatcher
Provide a Cooperative Processing facility for sessions
Public Class Methods
new(interval=0.333, thread_reservation=100)
click to toggle source
Calls superclass method
# File lib/gxg/gxg_events.rb, line 114 def initialize(interval=0.333, thread_reservation=100) super() @reserved_threads = (thread_reservation.to_i || 100) @uuid = ::GxG::uuid_generate().to_sym @event_queues = {:root => {:events => [], :settings => {:active => true, :portion => 100.0}}} @running = false @ticking = false # Timer format: {:when => Time_Object.to_f, :what => event_frame, :interval => float, :id => uuid.sym} @timers = [] @scheduler = Rufus::Scheduler.new(:max_work_threads => @reserved_threads) def @scheduler.on_error(job, error) log_error({:error => error, :parameters => {:job => job}}) end @scheduler.pause @tick_timer = nil @tick_interval = interval # self end
Public Instance Methods
adjust_event_queue(queue=:root,settings={})
click to toggle source
# File lib/gxg/gxg_events.rb, line 259 def adjust_event_queue(queue=:root,settings={}) # RESEARCH: GxG::Events::EventDispatcher.adjust_event_queue : refactor :portion of each queue algo needed. unless queue.to_s.to_sym == :root if @event_queues[(queue.to_sym)] # LATER: Eventually add :portion as valid setting to accept. [:active].each do |the_setting| if settings[(the_setting.to_sym)] new_setting = {} # portion adjustment algo here new_setting[(the_setting.to_sym)] = settings[(the_setting.to_sym)] # @event_queues[(queue.to_sym)][:settings].merge!(new_setting) end end else puts "Warning: queue #{queue.inspect} does not exist" # For Now: just ignore references to non-existent queues. (reconsider later) # raise ArgumentError, "Event Queue :#{queue} does not exist to alter" end end end
at(expression="",&block)
click to toggle source
# File lib/gxg/gxg_events.rb, line 364 def at(expression="",&block) the_time = nil case expression.class when ::DateTime the_time = expression.to_time() when ::Time the_time = expression when ::String the_time = ::Chronic::parse(expression) unless the_time raise ArgumentError, "Invalid time expression: #{expression.inspect}" end else raise ArgumentError, "Invalid time expression: #{expression.inspect}" end if the_time @scheduler.at(the_time.iso8601,&block) else nil end end
cancel_timer(timer_reference=nil)
click to toggle source
Adding Timers See: stackoverflow.com/questions/235504/validating-crontab-entries-with-php Cron REGEX: /^((?:[1-9]?d|*)s*(?:(?:[1-9]?d)|(?:,?d)+)?s*){5}$/ Rufus Duration REGEX: /^(-?)([d.smhdwy]+)$/ at, in, every, cron
# File lib/gxg/gxg_events.rb, line 354 def cancel_timer(timer_reference=nil) @scheduler.jobs().each do |the_task| if the_task.job_id == timer_reference the_task.unschedule break end end true end
create_event_queue(settings={})
click to toggle source
# File lib/gxg/gxg_events.rb, line 281 def create_event_queue(settings={}) unless settings.is_a?(Hash) raise ArgumentError, "you must provide a Hash as a parameter set" end queue_name = settings.delete(:name).to_s.to_sym if queue_name.to_s.size > 0 if @event_queues[(queue_name)] raise ArgumentError, "Event Queue #{queue_name.inspect} already exists" else @event_queues[(queue_name)] = {:events => [], :settings => {:active => false, :portion => 0.0}} # For Now: simply evenly divide the portions equally, only :root can be 100%. even_portion = (100.0 / @event_queues.keys.size.to_f) @event_queues.keys.each do |the_queue| @event_queues[(the_queue)][:settings][:portion] = (even_portion) end self.adjust_event_queue(queue_name, settings.merge({:active => true})) true end else raise ArgumentError, ":name must be provided for Event Queue" end end
cron(expression="",&block)
click to toggle source
# File lib/gxg/gxg_events.rb, line 496 def cron(expression="",&block) if /^((?:[1-9]?\d|\*)\s*(?:(?:[\/-][1-9]?\d)|(?:,[1-9]?\d)+)?\s*){5}$/.match(expression) @scheduler.cron(expression,&block) else raise ArgumentError, "Invalid CRON expression: #{expression.inspect}" end end
delete_event_queue(queue=nil)
click to toggle source
# File lib/gxg/gxg_events.rb, line 304 def delete_event_queue(queue=nil) if queue.to_s.to_sym == :root false else @event_queues.delete(queue) # For Now: simply evenly divide the portions equally, only :root can be 100%. even_portion = (@event_queues.keys.size.to_f / 100.0) @event_queues.keys.each do |the_queue| @event_queues[(the_queue)][:settings][:portion] = (even_portion) end true end end
every(expression="", &block)
click to toggle source
# File lib/gxg/gxg_events.rb, line 441 def every(expression="", &block) if expression.is_a?(::Numeric) interval = expression else if expression.include?(" ") # parse to Rufus duration duration_type = nil interval = nil expression.split(" ").each do |entry| if duration_type && interval break else if ["s","second", "seconds"].include?(entry) duration_type = "s" end if ["m","minute", "minutes"].include?(entry) duration_type = "m" end if ["h","hour", "hours"].include?(entry) duration_type = "h" end if ["d","day", "days"].include?(entry) duration_type = "d" end if ["w","week", "weeks"].include?(entry) duration_type = "w" end if /[-+0-9.,]*/.match(entry).to_s.size > 0 if entry.include?(".") interval = entry.to_f else interval = entry.to_i end end end end the_interval = (interval.to_s + duration_type.to_s) else # Verify standard Rufus expression duration_type = expression.split(/[-+0-9.,]*/)[1].to_s if ["s","m","h","d","w"].include?(duration_type.downcase) interval = /[-+0-9.,]*/.match(expression).to_s.to_i if interval > 0 the_interval = (interval.to_s + duration_type.to_s) else raise ArgumentError, "Invalid interval expression: #{expression.inspect}" end else raise ArgumentError, "Invalid interval expression: #{expression.inspect}" end end end @scheduler.every(the_interval,&block) end
in(expression="", &block)
click to toggle source
# File lib/gxg/gxg_events.rb, line 386 def in(expression="", &block) if expression.is_a?(::Numeric) interval = expression else if expression.include?(" ") # parse to Rufus duration duration_type = nil interval = nil expression.split(" ").each do |entry| if duration_type && interval break else if ["s","second", "seconds"].include?(entry) duration_type = "s" end if ["m","minute", "minutes"].include?(entry) duration_type = "m" end if ["h","hour", "hours"].include?(entry) duration_type = "h" end if ["d","day", "days"].include?(entry) duration_type = "d" end if ["w","week", "weeks"].include?(entry) duration_type = "w" end if /[-+0-9.,]*/.match(entry).to_s.size > 0 if entry.include?(".") interval = entry.to_f else interval = entry.to_i end end end end interval = (interval.to_s + duration_type.to_s) else # Verify standard Rufus expression duration_type = expression.split(/[-+0-9.,]*/)[1].to_s if ["s","m","h","d","w"].include?(duration_type.downcase) interval = /[-+0-9.,]*/.match(expression).to_s.to_i if interval > 0 interval = (interval.to_s + duration_type.to_s) else raise ArgumentError, "Invalid interval expression: #{expression.inspect}" end else raise ArgumentError, "Invalid interval expression: #{expression.inspect}" end end end @scheduler.in(interval,&block) end
inspect_queue(queue=:root)
click to toggle source
# File lib/gxg/gxg_events.rb, line 255 def inspect_queue(queue=:root) @event_queues[(queue)] end
inspect_timers()
click to toggle source
# File lib/gxg/gxg_events.rb, line 252 def inspect_timers() @scheduler.jobs() end
pause_event_queue(queue=nil)
click to toggle source
# File lib/gxg/gxg_events.rb, line 318 def pause_event_queue(queue=nil) unless queue.to_s.to_sym == :root self.adjust_event_queue(queue,{:active => true}) end end
post_event(queue_name=:root,&block)
click to toggle source
# File lib/gxg/gxg_events.rb, line 341 def post_event(queue_name=:root,&block) unless @event_queues[(queue_name.to_sym)] self.create_event_queue({:name => queue_name.to_sym}) end self.post_to_event_queue(queue_name.to_sym,block) true end
post_to_event_queue(queue=:root,the_event=nil)
click to toggle source
# File lib/gxg/gxg_events.rb, line 330 def post_to_event_queue(queue=:root,the_event=nil) if the_event.respond_to?(:call) if @event_queues[(queue)] @event_queues[(queue)][:events] << the_event else # issue a warning, and post to :root queue anyways (for now). (link to logger, and output) @event_queues[:root][:events] << the_event end end end
running?()
click to toggle source
# File lib/gxg/gxg_events.rb, line 134 def running?() @running end
shutdown()
click to toggle source
# File lib/gxg/gxg_events.rb, line 159 def shutdown() @running = false if @tick_timer self.cancel_timer(@tick_timer) @tick_timer = nil @scheduler.pause @reserved_threads.times do ::GxG::Engine::release_event_descriptor() end end true end
startup()
click to toggle source
# File lib/gxg/gxg_events.rb, line 138 def startup() @running = true if @scheduler.paused? @scheduler.resume end unless @tick_timer @tick_timer = @scheduler.every(@tick_interval) do tick end end @reserved_threads.times do begin ::GxG::Engine::reserve_event_descriptor() rescue Exception => the_error log_error({:error => the_error}) break end end @running end
tick()
click to toggle source
# File lib/gxg/gxg_events.rb, line 172 def tick() if @running unless @ticking @ticking = true events = [] envelope = ::GxG::Engine::event_allocation_envelope() if envelope.last >= envelope.first prefetch = {} @event_queues.keys.each do |the_queue| if (@event_queues[(the_queue)][:settings][:active] && @event_queues[(the_queue)][:events].size > 0) ((@event_queues[(the_queue)][:settings][:portion].to_f / 100.0) * envelope.last.to_f).to_i.times do op = @event_queues[(the_queue)][:events].shift if op.respond_to?(:call) (prefetch[(the_queue)] ||= []) << op end end end end # prefetch_count = 0 prefetch.keys.each do |the_queue| prefetch_count += prefetch[(the_queue)].size end # while prefetch_count > 0 do prefetch.keys.each do |the_queue| op = prefetch[(the_queue)].shift if op events << op end prefetch_count -= 1 end end # end # xxx old version: # queues = {} # load_size = 0 # @event_queues.keys.each do |the_queue| # if (@event_queues[(the_queue)][:settings][:active] && @event_queues[(the_queue)][:events].size > 0) # queues[(the_queue)] = {:portion => ((@event_queues[(the_queue)][:settings][:portion].to_f / 100.0) * total_slots.to_f).to_i} # if queues[(the_queue)][:portion] == 0 # # Fudging a little here in case of real heavy loads and/or too many queues. # queues[(the_queue)][:portion] = 1 # end # queues[(the_queue)][:size] = @event_queues[(the_queue)][:events].size # load_size += queues[(the_queue)][:size] # end # end # queues.keys.each do |the_queue| # # TODO: devise apportioned event dispatch # queues[(the_queue)][:portion].times do # op = @event_queues[(the_queue)][:events].shift # if op.respond_to?(:call) # events << op # else # break # end # end # end # events.each do |the_event| if the_event Thread.new do ::GxG::Engine::reserve_event_descriptor() begin the_event.call() rescue Exception => the_error log_error({:error => the_error}) end ::GxG::Engine::release_event_descriptor() end end end # @ticking = false end end end
unpause_event_queue(queue=nil)
click to toggle source
# File lib/gxg/gxg_events.rb, line 324 def unpause_event_queue(queue=nil) unless queue.to_s.to_sym == :root self.adjust_event_queue(queue,{:active => false}) end end