Class: Actor
- Inherits:
-
Object
- Object
- Actor
- Defined in:
- lib/revactor.rb,
lib/revactor/actor.rb,
lib/revactor/mailbox.rb,
lib/revactor/scheduler.rb
Overview
– Copyright ©2007 Tony Arcieri You can redistribute this under the terms of the Ruby license See file LICENSE for details ++
Defined Under Namespace
Constant Summary collapse
- TCP =
Revactor::TCP
- UNIX =
Revactor::UNIX
- Filter =
Revactor::Filter
- HttpClient =
Revactor::HttpClient
- @@registered =
{}
Instance Attribute Summary collapse
-
#fiber ⇒ Object
readonly
Returns the value of attribute fiber.
-
#mailbox ⇒ Object
readonly
Returns the value of attribute mailbox.
-
#scheduler ⇒ Object
readonly
Returns the value of attribute scheduler.
Class Method Summary collapse
-
.[](key) ⇒ Object
Look up an actor in the global dictionary.
-
.[]=(key, actor) ⇒ Object
Register this actor in the global dictionary.
-
.current ⇒ Object
Obtain a handle to the current Actor.
-
.delete(key, &block) ⇒ Object
Delete an actor from the global dictionary.
-
.link(actor) ⇒ Object
Link the current Actor to another one.
-
.receive(&filter) ⇒ Object
Wait for messages matching a given filter.
-
.reschedule ⇒ Object
Reschedule the current actor for execution later.
-
.scheduler ⇒ Object
Obtain a handle to the current Scheduler.
-
.sleep(seconds) ⇒ Object
Sleep for the specified number of seconds.
-
.spawn(*args, &block) ⇒ Object
Create a new Actor with the given block and arguments.
-
.spawn_link(*args, &block) ⇒ Object
Spawn an Actor and immediately link it to the current one.
-
.tick ⇒ Object
Run the event loop and return after processing all outstanding messages.
-
.unlink(actor) ⇒ Object
Unlink the current Actor from another one.
Instance Method Summary collapse
-
#<<(message) ⇒ Object
(also: #send)
Send a message to an actor.
-
#[](key) ⇒ Object
Look up value in the actor’s dictionary.
-
#[]=(key, value) ⇒ Object
Store a value in the actor’s dictionary.
-
#dead? ⇒ Boolean
Is the current actor dead?.
-
#delete(key, &block) ⇒ Object
Delete a value from the actor’s dictionary.
-
#initialize(fiber = Fiber.current) ⇒ Actor
constructor
A new instance of Actor.
-
#link(actor) ⇒ Object
Establish a bidirectional link to the given Actor and notify it of any system events which occur in this Actor (namely exits due to exceptions).
-
#notify_exited(actor, reason) ⇒ Object
Notify this actor that one of the Actors it’s linked to has exited.
-
#notify_link(actor) ⇒ Object
Notify this actor that it’s now linked to the given one.
-
#notify_unlink(actor) ⇒ Object
Notify this actor that it’s now unlinked from the given one.
-
#trap_exit=(value) ⇒ Object
Actors trapping exit do not die when an error occurs in an Actor they are linked to.
-
#trap_exit? ⇒ Boolean
Is the Actor trapping exit?.
-
#unlink(actor) ⇒ Object
Unestablish a link with the given actor.
Constructor Details
#initialize(fiber = Fiber.current) ⇒ Actor
Returns a new instance of Actor.
152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/revactor/actor.rb', line 152 def initialize(fiber = Fiber.current) raise ArgumentError, "use Actor.spawn to create actors" if block_given? @fiber = fiber @scheduler = Actor.scheduler @thread = Thread.current @mailbox = Mailbox.new @links = [] @events = [] @trap_exit = false @dead = false @dictionary = {} end |
Instance Attribute Details
#fiber ⇒ Object (readonly)
Returns the value of attribute fiber.
39 40 41 |
# File 'lib/revactor/actor.rb', line 39 def fiber @fiber end |
#mailbox ⇒ Object (readonly)
Returns the value of attribute mailbox.
41 42 43 |
# File 'lib/revactor/actor.rb', line 41 def mailbox @mailbox end |
#scheduler ⇒ Object (readonly)
Returns the value of attribute scheduler.
40 41 42 |
# File 'lib/revactor/actor.rb', line 40 def scheduler @scheduler end |
Class Method Details
.[](key) ⇒ Object
Look up an actor in the global dictionary
119 120 121 |
# File 'lib/revactor/actor.rb', line 119 def [](key) @@registered[key] end |
.[]=(key, actor) ⇒ Object
Register this actor in the global dictionary
124 125 126 127 128 129 130 |
# File 'lib/revactor/actor.rb', line 124 def []=(key, actor) unless actor.is_a?(Actor) raise ArgumentError, "only actors may be registered" end @@registered[key] = actor end |
.current ⇒ Object
Obtain a handle to the current Actor
76 77 78 |
# File 'lib/revactor/actor.rb', line 76 def current Fiber.current._actor end |
.delete(key, &block) ⇒ Object
Delete an actor from the global dictionary
133 134 135 |
# File 'lib/revactor/actor.rb', line 133 def delete(key, &block) @@registered.delete(key, &block) end |
.link(actor) ⇒ Object
Link the current Actor to another one
66 67 68 |
# File 'lib/revactor/actor.rb', line 66 def link(actor) current.link actor end |
.receive(&filter) ⇒ Object
Wait for messages matching a given filter. The filter object is yielded to be block passed to receive. You can then invoke the when argument which takes a parameter and a block. Messages are compared (using ===) against the parameter. The Case gem includes several tools for matching messages using ===
The first filter to match a message in the mailbox is executed. If no filters match then the actor sleeps.
114 115 116 |
# File 'lib/revactor/actor.rb', line 114 def receive(&filter) current.mailbox.receive(&filter) end |
.reschedule ⇒ Object
Reschedule the current actor for execution later
86 87 88 89 90 91 92 93 94 |
# File 'lib/revactor/actor.rb', line 86 def reschedule if scheduler.running? Fiber.yield else scheduler << current end current.__send__(:process_events) end |
.scheduler ⇒ Object
Obtain a handle to the current Scheduler
81 82 83 |
# File 'lib/revactor/actor.rb', line 81 def scheduler Thread.current._revactor_scheduler end |
.sleep(seconds) ⇒ Object
Sleep for the specified number of seconds
97 98 99 |
# File 'lib/revactor/actor.rb', line 97 def sleep(seconds) receive { |filter| filter.after(seconds) } end |
.spawn(*args, &block) ⇒ Object
Create a new Actor with the given block and arguments
47 48 49 50 51 52 53 |
# File 'lib/revactor/actor.rb', line 47 def spawn(*args, &block) raise ArgumentError, "no block given" unless block actor = _spawn(*args, &block) scheduler << actor actor end |
.spawn_link(*args, &block) ⇒ Object
Spawn an Actor and immediately link it to the current one
56 57 58 59 60 61 62 63 |
# File 'lib/revactor/actor.rb', line 56 def spawn_link(*args, &block) raise ArgumentError, "no block given" unless block actor = _spawn(*args, &block) current.link actor scheduler << actor actor end |
.tick ⇒ Object
Run the event loop and return after processing all outstanding messages
102 103 104 |
# File 'lib/revactor/actor.rb', line 102 def tick sleep 0 end |
.unlink(actor) ⇒ Object
Unlink the current Actor from another one
71 72 73 |
# File 'lib/revactor/actor.rb', line 71 def unlink(actor) current.unlink actor end |
Instance Method Details
#<<(message) ⇒ Object Also known as: send
Send a message to an actor
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/revactor/actor.rb', line 187 def <<() # Use the scheduler mailbox to send messages across threads unless @thread == Thread.current scheduler.mailbox.send(self, ) return end # Erlang discards messages sent to dead actors, and if Erlang does it, # it must be the right thing to do, right? Hooray for the Erlang # cargo cult! I think they do this because dealing with errors raised # from dead actors greatly overcomplicates overall error handling return if dead? @mailbox << @scheduler << self end |
#[](key) ⇒ Object
Look up value in the actor’s dictionary
169 170 171 |
# File 'lib/revactor/actor.rb', line 169 def [](key) @dictionary[key] end |
#[]=(key, value) ⇒ Object
Store a value in the actor’s dictionary
174 175 176 |
# File 'lib/revactor/actor.rb', line 174 def []=(key, value) @dictionary[key] = value end |
#dead? ⇒ Boolean
Is the current actor dead?
184 |
# File 'lib/revactor/actor.rb', line 184 def dead?; @dead; end |
#delete(key, &block) ⇒ Object
Delete a value from the actor’s dictionary
179 180 181 |
# File 'lib/revactor/actor.rb', line 179 def delete(key, &block) @dictionary.delete(key, &block) end |
#link(actor) ⇒ Object
Establish a bidirectional link to the given Actor and notify it of any system events which occur in this Actor (namely exits due to exceptions)
210 211 212 213 |
# File 'lib/revactor/actor.rb', line 210 def link(actor) actor.notify_link self self.notify_link actor end |
#notify_exited(actor, reason) ⇒ Object
Notify this actor that one of the Actors it’s linked to has exited
245 246 247 |
# File 'lib/revactor/actor.rb', line 245 def notify_exited(actor, reason) @events << T[:exit, actor, reason] end |
#notify_link(actor) ⇒ Object
Notify this actor that it’s now linked to the given one
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/revactor/actor.rb', line 222 def notify_link(actor) raise ArgumentError, "can only link to Actors" unless actor.is_a? Actor # Don't allow linking to dead actors raise DeadActorError, "actor is dead" if actor.dead? # Ignore circular links return true if actor == self # Ignore duplicate links return true if @links.include? actor @links << actor true end |
#notify_unlink(actor) ⇒ Object
Notify this actor that it’s now unlinked from the given one
239 240 241 242 |
# File 'lib/revactor/actor.rb', line 239 def notify_unlink(actor) @links.delete(actor) true end |
#trap_exit=(value) ⇒ Object
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.
254 255 256 257 |
# File 'lib/revactor/actor.rb', line 254 def trap_exit=(value) raise ArgumentError, "must be true or false" unless value == true or value == false @trap_exit = value end |
#trap_exit? ⇒ Boolean
Is the Actor trapping exit?
260 261 262 |
# File 'lib/revactor/actor.rb', line 260 def trap_exit? @trap_exit end |
#unlink(actor) ⇒ Object
Unestablish a link with the given actor
216 217 218 219 |
# File 'lib/revactor/actor.rb', line 216 def unlink(actor) actor.notify_unlink self self.notify_unlink actor end |