Class: Thespian::Actor
- Inherits:
-
Object
- Object
- Thespian::Actor
- Defined in:
- lib/thespian/actor.rb
Constant Summary collapse
- STATE_INITIALIZED =
The state an actor is in after it has been created, but before it enters the message processing loop.
:initialized- STATE_RUNNING =
The state for when an actor is in the message processing loop.
:running- STATE_FINISHED =
The state for when an actor has exited the message processing loop (either by error or intentially).
:finished- DEFAULT_OPTIONS =
{ :strict => true, :trap_exit => false, :object => nil }
Instance Attribute Summary collapse
-
#exception ⇒ Object
readonly
If an actor died due to an exception, it is stored here.
-
#state ⇒ Object
readonly
Returns the actor’s state.
Instance Method Summary collapse
-
#<<(message) ⇒ Object
Add a message to the actor’s mailbox.
-
#error? ⇒ Boolean
Returns true if an error occurred that caused the actor to enter the :finished state.
-
#finished? ⇒ Boolean
#state == :finished.
-
#initialize(options = {}, &block) ⇒ Actor
constructor
call-seq: new(options = {}){ |message| … }.
-
#initialized? ⇒ Boolean
#state == :initialized.
-
#link(object) ⇒ Object
call-seq: link(actor).
-
#options(arg = nil) ⇒ Object
call-seq: options -> Hash options(hash) -> Hash options(symbol) -> value.
-
#running? ⇒ Boolean
#state == :running.
-
#salvage_mailbox ⇒ Object
Salvage mailbox contents from a dead actor (including the message it died on).
-
#start ⇒ Object
Start the actor’s message processing loop.
-
#stop ⇒ Object
Stop the actor.
Constructor Details
#initialize(options = {}, &block) ⇒ Actor
call-seq:
new( = {}){ || ... }
Create a new actor using the given block to handles messages. The actor will be in the :initialized state, meaning the message processing loop hasn’t started yet (see #start).
options are the same as specified by #options.
38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/thespian/actor.rb', line 38 def initialize( = {}, &block) self.(DEFAULT_OPTIONS.merge()) @state = :initialized @receive_block = block @linked_actors = Set.new @mailbox = [] @mailbox_lock = Monitor.new @mailbox_cond = @mailbox_lock.new_cond end |
Instance Attribute Details
#exception ⇒ Object (readonly)
If an actor died due to an exception, it is stored here.
11 12 13 |
# File 'lib/thespian/actor.rb', line 11 def exception @exception end |
#state ⇒ Object (readonly)
Returns the actor’s state.
14 15 16 |
# File 'lib/thespian/actor.rb', line 14 def state @state end |
Instance Method Details
#<<(message) ⇒ Object
Add a message to the actor’s mailbox. May raise an exception according to #check_alive!
132 133 134 135 136 137 138 139 140 |
# File 'lib/thespian/actor.rb', line 132 def <<() check_alive! if (:strict) = .new if == Stop @mailbox_lock.synchronize do @mailbox << @mailbox_cond.signal end self end |
#error? ⇒ Boolean
Returns true if an error occurred that caused the actor to enter the :finished state.
168 169 170 |
# File 'lib/thespian/actor.rb', line 168 def error? !!@exception end |
#finished? ⇒ Boolean
#state == :finished
163 164 165 |
# File 'lib/thespian/actor.rb', line 163 def finished? state == :finished end |
#initialized? ⇒ Boolean
#state == :initialized
153 154 155 |
# File 'lib/thespian/actor.rb', line 153 def initialized? state == :initialized end |
#link(object) ⇒ Object
call-seq:
link(actor)
Exceptions in actors will be propogated to actors that are linked to them. How they are propogated is determined by the :trap_exit option (see #options).
actor can either be an Actor instance or an instance of a class that included Thespian.
87 88 89 90 91 |
# File 'lib/thespian/actor.rb', line 87 def link(object) actor = object.kind_of?(Actor) ? object : object.actor actor.send(:_link, self) object end |
#options(arg = nil) ⇒ Object
call-seq:
-> Hash
(hash) -> Hash
(symbol) -> value
Get or set options. Valid options are:
- :strict (default true)
-
Require an actor to be running in order to put messages into its mailbox.
- :trap_exit (default false)
-
If true, the actor will get a DeadActorError message in its mailbox when a linked actor raises an unhandled exception.
If given no arguments, returns a hash of options.
If given a hash, sets the options specified in the hash.
If given a symbol, returns that option’s value.
67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/thespian/actor.rb', line 67 def (arg = nil) ||= {} case arg when Hash .merge!(arg) when Symbol [arg] when nil end end |
#running? ⇒ Boolean
#state == :running
158 159 160 |
# File 'lib/thespian/actor.rb', line 158 def running? state == :running end |
#salvage_mailbox ⇒ Object
Salvage mailbox contents from a dead actor (including the message it died on). Useful for restarting a dead actor while preserving its mailbox.
174 175 176 177 178 179 |
# File 'lib/thespian/actor.rb', line 174 def salvage_mailbox raise "cannot salvage mailbox from an actor that isn't finished" unless state == :finished @mailbox.dup.tap do |mailbox| mailbox.unshift() if end end |
#start ⇒ Object
Start the actor’s message processing loop. The thread that the loop is run on is guaranteed to have started by the time this method returns.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/thespian/actor.rb', line 95 def start # Don't let them start an already started actor. raise "already running" if running? # Can't raise an actor from the dead. raise @exception if @exception # IMPORTANT - Race condition! # This method and the thread both set @state. We don't want this method to # possibly overwrite how the thread sets @state, so we set the @state # before staring the thread. @state = :running # Declare local synchronization vars. lock = Monitor.new cond = lock.new_cond wait = true # Start the thread and have it signal when it's running. @thread = Thread.new do Thread.current[:actor] = (:object).to_s lock.synchronize do wait = false cond.signal end run end # Block until the thread has signaled that it's running. lock.synchronize do cond.wait_while{ wait } end end |
#stop ⇒ Object
Stop the actor. All pending messages will be processed before stopping the actor. Raises an exception if the actor is not #running? and :strict (see #options) is true.
145 146 147 148 149 150 |
# File 'lib/thespian/actor.rb', line 145 def stop check_alive! if (:strict) self << Stop.new @thread.join raise @exception if @exception end |