module Tribe::Actable
Public Instance Methods
alive?()
click to toggle source
# File lib/tribe/actable.rb, line 92 def alive? @_actable.mailbox.alive? end
dead?()
click to toggle source
# File lib/tribe/actable.rb, line 96 def dead? !alive? end
deliver_event!(event)
click to toggle source
Thread safe public methods. Notes: These are the methods that actors use to communicate with each other.
Actors should avoid sharing mutable state in order to remain thread safe. Methods with a ! are designed for asynchronous communication.
# File lib/tribe/actable.rb, line 46 def deliver_event!(event) @_actable.mailbox.push(event) do process_events end nil end
direct_message!(command, data = nil, src = nil)
click to toggle source
# File lib/tribe/actable.rb, line 54 def direct_message!(command, data = nil, src = nil) deliver_event!(Tribe::Event.new(command, data, src)) nil end
exception()
click to toggle source
# File lib/tribe/actable.rb, line 108 def exception @_actable.exception end
identifier()
click to toggle source
# File lib/tribe/actable.rb, line 104 def identifier @_actable.name ? "#{object_id}:#{@_actable.name}" : object_id end
logger()
click to toggle source
# File lib/tribe/actable.rb, line 120 def logger @_actable.logger end
name()
click to toggle source
# File lib/tribe/actable.rb, line 100 def name @_actable.name end
perform!(&block)
click to toggle source
# File lib/tribe/actable.rb, line 64 def perform!(&block) direct_message!(:__perform__, block) end
pool()
click to toggle source
# File lib/tribe/actable.rb, line 116 def pool @_actable.pool end
registry()
click to toggle source
# File lib/tribe/actable.rb, line 112 def registry @_actable.registry end
shutdown!()
click to toggle source
# File lib/tribe/actable.rb, line 60 def shutdown! direct_message!(:__shutdown__) end
spawn!(klass, actor_options = {}, spawn_options = {})
click to toggle source
# File lib/tribe/actable.rb, line 68 def spawn!(klass, actor_options = {}, spawn_options = {}) actor_options[:parent] = self child = nil if spawn_options[:no_raise_on_failure] begin child = klass.new(actor_options) rescue Exception return false end else child = klass.new(actor_options) end @_actable.children.add(child) if spawn_options[:supervise] @_actable.supervisees.add(child) end child end
Private Instance Methods
blocking!() { || ... }
click to toggle source
Wrap blocking code using this method to automatically expand/contract the pool. This way you avoid potential thread starvation. Not needed for dedicated actors since they already have their own thread.
# File lib/tribe/actable.rb, line 355 def blocking! if @_actable.dedicated yield else pool.expand(1) begin yield ensure pool.contract(1) end end end
child_died_handler(child, exception)
click to toggle source
# File lib/tribe/actable.rb, line 267 def child_died_handler(child, exception) @_actable.children.delete(child) supervising = !!@_actable.supervisees.delete?(child) on_child_died(Event.new(:child_died, {:child => child, :exception => exception})) if !supervising raise Tribe::ActorChildDied.new("#{child.identifier} died.") end nil end
child_shutdown_handler(child)
click to toggle source
# File lib/tribe/actable.rb, line 280 def child_shutdown_handler(child) @_actable.children.delete(child) @_actable.supervisees.delete(child) on_child_shutdown(Event.new(:child_shutdown, {:child => child})) nil end
cleanup_handler(exception = nil)
click to toggle source
# File lib/tribe/actable.rb, line 257 def cleanup_handler(exception = nil) @_actable.exception = exception @_actable.pool.shutdown if @_actable.dedicated @_actable.mailbox.kill @_actable.registry.unregister(self) @_actable.timers.each { |t| t.cancel } if @_actable.timers nil end
custom_event_handler(event)
click to toggle source
# File lib/tribe/actable.rb, line 195 def custom_event_handler(event) result = nil @_actable.active_event = event begin result = send("on_#{event.command}", event) rescue Exception => e result = e raise ensure if event.future && @_actable.active_event event.future.result = result end @_actable.active_event = nil end nil end
event_handler(event)
click to toggle source
# File lib/tribe/actable.rb, line 173 def event_handler(event) case event.command when :__initialize__ initialize_handler(event) when :__shutdown__ cleanup_handler shutdown_handler(event) when :__perform__ perform_handler(event) when :__child_died__ child_died_handler(event.data[0], event.data[1]) when :__child_shutdown__ child_shutdown_handler(event.data) when :__parent_died__ parent_died_handler(event.data[0], event.data[1]) when :initialize, :shutdown, :perform, :child_died, :child_shutdown, :parent_died raise ActorReservedCommand.new("Reserved commands are not allowed (command=#{event.command}).") else custom_event_handler(event) end end
exception_handler(exception)
click to toggle source
# File lib/tribe/actable.rb, line 218 def exception_handler(exception) if @_actable.parent @_actable.parent.direct_message!(:__child_died__, [self, exception]) end @_actable.children.each { |c| c.direct_message!(:__parent_died__, [self, exception]) } @_actable.children.clear @_actable.supervisees.clear log_exception_handler(exception) on_exception(Event.new(:exception, {:exception => exception})) nil end
forward!(dest)
click to toggle source
# File lib/tribe/actable.rb, line 345 def forward!(dest) dest.deliver_event!(@_actable.active_event) @_actable.active_event = nil nil end
future!(dest, command, data = nil)
click to toggle source
# File lib/tribe/actable.rb, line 311 def future!(dest, command, data = nil) event = Tribe::Event.new(command, data, self) event.future = future = Tribe::Future.new(self) dest.deliver_event!(event) future end
init_actable(options = {})
click to toggle source
Initialization method. Notes: Call this in your constructor.
# File lib/tribe/actable.rb, line 12 def init_actable(options = {}) # Symbols aren't GCed in JRuby so force string names. if options[:name] && !options[:name].is_a?(String) raise Tribe::ActorNameError.new('Name must be a string.') end @_actable = Tribe::ActorState.new @_actable.dedicated = options[:dedicated] || false @_actable.pool = @_actable.dedicated ? Workers::Pool.new(:size => 1) : (options[:pool] || Workers.pool) @_actable.mailbox = Tribe::Mailbox.new(@_actable.pool) @_actable.registry = options[:registry] || Tribe.registry @_actable.logger = Workers::LogProxy.new(options[:logger] || Tribe.logger) @_actable.scheduler = options[:scheduler] || Workers.scheduler @_actable.name = options[:name] @_actable.parent = options[:parent] @_actable.children = Tribe::SafeSet.new @_actable.supervisees = Tribe::SafeSet.new @_actable.timers = Tribe::SafeSet.new @_actable.registry.register(self) direct_message!(:__initialize__) end
initialize_handler(event)
click to toggle source
# File lib/tribe/actable.rb, line 214 def initialize_handler(event) on_initialize(event) end
log_exception_handler(exception)
click to toggle source
# File lib/tribe/actable.rb, line 233 def log_exception_handler(exception) logger.error("EXCEPTION: #{exception.message}\n#{exception.backtrace.join("\n")}\n--") end
message!(dest, command, data = nil)
click to toggle source
Private API methods. Notes: Use these methods internally in your actor.
# File lib/tribe/actable.rb, line 303 def message!(dest, command, data = nil) event = Tribe::Event.new(command, data, self) dest.deliver_event!(event) nil end
on_child_died(event)
click to toggle source
# File lib/tribe/actable.rb, line 140 def on_child_died(event) end
on_child_shutdown(event)
click to toggle source
# File lib/tribe/actable.rb, line 143 def on_child_shutdown(event) end
on_exception(event)
click to toggle source
# File lib/tribe/actable.rb, line 134 def on_exception(event) end
on_initialize(event)
click to toggle source
Private command handlers. Notes: These methods are designed to be overriden in order to respond to actor system events.
# File lib/tribe/actable.rb, line 131 def on_initialize(event) end
on_parent_died(event)
click to toggle source
# File lib/tribe/actable.rb, line 146 def on_parent_died(event) end
on_shutdown(event)
click to toggle source
# File lib/tribe/actable.rb, line 137 def on_shutdown(event) end
parent_died_handler(parent, exception)
click to toggle source
# File lib/tribe/actable.rb, line 289 def parent_died_handler(parent, exception) on_parent_died(Event.new(:parent_died, {:parent => parent, :exception => exception})) raise Tribe::ActorParentDied.new("#{parent.identifier} died.") nil end
perform_handler(event)
click to toggle source
# File lib/tribe/actable.rb, line 251 def perform_handler(event) event.data.call nil end
periodic_timer!(delay, command, data = nil)
click to toggle source
# File lib/tribe/actable.rb, line 331 def periodic_timer!(delay, command, data = nil) timer = Workers::PeriodicTimer.new(delay, :scheduler => @_actable.scheduler) do direct_message!(command, data) unless alive? @_actable.timers.delete(timer) timer.cancel end end @_actable.timers.add(timer) timer end
process_events()
click to toggle source
All system commands are prefixed with an underscore.
# File lib/tribe/actable.rb, line 157 def process_events while (event = @_actable.mailbox.obtain_and_shift) event_handler(event) end rescue Exception => exception cleanup_handler(exception) exception_handler(exception) ensure @_actable.mailbox.release do process_events end nil end
shutdown_handler(event)
click to toggle source
# File lib/tribe/actable.rb, line 237 def shutdown_handler(event) if @_actable.parent @_actable.parent.direct_message!(:__child_shutdown__, self) end @_actable.children.each { |c| c.shutdown! } @_actable.children.clear @_actable.supervisees.clear on_shutdown(Event.new(:shutdown, {})) nil end
timer!(delay, command, data = nil)
click to toggle source
# File lib/tribe/actable.rb, line 320 def timer!(delay, command, data = nil) timer = Workers::Timer.new(delay, :scheduler => @_actable.scheduler) do @_actable.timers.delete(timer) direct_message!(command, data) end @_actable.timers.add(timer) timer end
wait!(future)
click to toggle source
# File lib/tribe/actable.rb, line 368 def wait!(future) blocking! do future.wait end end