class Actor
Constants
- ANY
Public Class Methods
Polls for exit notifications
# File lib/girl_friday/actor.rb, line 92 def check_for_interrupt current._check_for_interrupt self end
# File lib/girl_friday/actor.rb, line 57 def current Thread.current[:__current_actor__] ||= private_new end
Link the current Actor
to another one.
# File lib/girl_friday/actor.rb, line 118 def link(actor) current = self.current current.notify_link actor actor.notify_link current self end
Lookup a locally named service
# File lib/girl_friday/actor.rb, line 152 def lookup(name) raise ArgumentError, "name must be a symbol" unless Symbol === name @@registered_lock.pop begin @@registered[name] ensure @@registered_lock << nil end end
# File lib/girl_friday/actor.rb, line 193 def initialize @lock = Queue.new @filter = nil @ready = Queue.new @action = nil @message = nil @mailbox = [] @interrupts = [] @links = [] @alive = true @exit_reason = nil @trap_exit = false @thread = Thread.current @lock << nil if block_given? watchdog { yield self } else Thread.new { watchdog { @thread.join } } end end
Waits until a matching message is received in the current actor’s mailbox, and executes the appropriate action. May be interrupted by exit notifications.
# File lib/girl_friday/actor.rb, line 100 def receive #:yields: filter filter = Filter.new if block_given? yield filter else filter.when(ANY) { |m| m } end current._receive(filter) end
Register an Actor
locally as a named service
# File lib/girl_friday/actor.rb, line 164 def register(name, actor) raise ArgumentError, "name must be a symbol" unless Symbol === name unless actor.nil? or actor.is_a?(Actor) raise ArgumentError, "only actors may be registered" end @@registered_lock.pop begin if actor.nil? @@registered.delete(name) else @@registered[name] = actor end ensure @@registered_lock << nil end end
Send a “fake” exit notification to another actor, as if the current actor had exited with reason
# File lib/girl_friday/actor.rb, line 112 def send_exit(recipient, reason) recipient.notify_exited(current, reason) self end
Spawn a new Actor
that will run in its own thread
# File lib/girl_friday/actor.rb, line 62 def spawn(*args, &block) raise ArgumentError, "no block given" unless block spawned = Queue.new Thread.new do private_new do |actor| Thread.current[:__current_actor__] = actor spawned << actor block.call(*args) end end spawned.pop end
Atomically spawn an actor and link it to the current actor
# File lib/girl_friday/actor.rb, line 77 def spawn_link(*args, &block) current = self.current link_complete = Queue.new spawn do begin Actor.link(current) ensure link_complete << Actor.current end block.call(*args) end link_complete.pop end
Is the Actor
trapping exit?
# File lib/girl_friday/actor.rb, line 146 def trap_exit current._trap_exit end
Actors trapping exit do not die when an error occurs in an Actor
they are linked to. Instead the exit message is sent to their regular mailbox in the form [:exit, actor, reason]. This allows certain Actors to supervise sets of others and restart them in the event of an error. Setting the trap flag may be interrupted by pending exit notifications.
# File lib/girl_friday/actor.rb, line 140 def trap_exit=(value) current._trap_exit = value self end
Unlink the current Actor
from another one
# File lib/girl_friday/actor.rb, line 126 def unlink(actor) current = self.current current.notify_unlink actor actor.notify_unlink current self end
Public Instance Methods
Notify this actor that one of the Actors it’s linked to has exited; this is not intended to be used directly except by actor implementations. Most users will want to use Actor.send_exit
instead.
# File lib/girl_friday/actor.rb, line 352 def notify_exited(actor, reason) exit_message = nil @lock.pop begin return self unless @alive @links.delete(actor) if @trap_exit exit_message = DeadActorError.new(actor, reason) elsif reason @interrupts << DeadActorError.new(actor, reason) if @filter @filter = nil @ready << nil end end ensure @lock << nil end send exit_message if exit_message self end
Notify this actor that it’s now linked to the given one; this is not intended to be used directly except by actor implementations. Most users will want to use Actor.link
instead.
# File lib/girl_friday/actor.rb, line 318 def notify_link(actor) @lock.pop alive = nil exit_reason = nil begin alive = @alive exit_reason = @exit_reason @links << actor if alive and not @links.include? actor ensure @lock << nil end actor.notify_exited(self, exit_reason) unless alive self end
Notify this actor that it’s now unlinked from the given one; this is not intended to be used directly except by actor implementations. Most users will want to use Actor.unlink
instead.
# File lib/girl_friday/actor.rb, line 337 def notify_unlink(actor) @lock.pop begin return self unless @alive @links.delete(actor) ensure @lock << nil end self end
# File lib/girl_friday/actor.rb, line 218 def send(message) @lock.pop begin return self unless @alive if @filter @action = @filter.action_for(message) if @action @filter = nil @message = message @ready << nil else @mailbox << message end else @mailbox << message end ensure @lock << nil end self end
Private Instance Methods
# File lib/girl_friday/actor.rb, line 403 def check_thread unless Thread.current == @thread raise ThreadError, "illegal cross-actor call" end end
# File lib/girl_friday/actor.rb, line 374 def watchdog reason = nil begin yield rescue Exception => reason ensure links = nil Actor._unregister(self) @lock.pop begin @alive = false @mailbox = nil @interrupts = nil @exit_reason = reason links = @links @links = nil ensure @lock << nil end links.each do |actor| begin actor.notify_exited(self, reason) rescue Exception end end end end