Index
Actors.AbsMinder
Actors.AbsStage
Actors.Actor
Actors.Actor
Actors.AsyncFail!
Actors.Died!
Actors.Genesis!
Actors.Id
Actors.Invite!
Actors.Invited!
Actors.Leave!
Actors.Left!
Actors.Logger
Actors.PreGenesis!
Actors.Scene
Actors.Shout!
Actors.Stage
Actors.Stooge
Actors.TreeMinder
Actors.Troupe
Actors.ask
Actors.async
Actors.capture_environment
Actors.delegate
Actors.dieing_breath!
Actors.enter!
Actors.epilogue!
Actors.expect
Actors.fork
Actors.hear
Actors.inbox
Actors.interact!
Actors.interact!
Actors.invite!
Actors.leave!
Actors.listen!
Actors.local_addresses
Actors.me
Actors.minder
Actors.my
Actors.play!
Actors.prologue!
Actors.say
Actors.shout
Actors.shout
Actors.stage
Actors.try_say
Actors.@say_info
Reference
Actors.AbsMinder
— TypeActors.AbsStage
— TypeActors.Actor
— TypeThe star of the show (but not really)
This holds internal state for an Actor, it wraps the user defined state value. We usually think of the Actor as being the state value rather than this structure which is mostely hidden. It is rare that a user will need to access this directly. Usually Actors are referenced by an Id
and we get the actor's details by calling accessor functions on either the Id
or the Scene
.
If you do access this, then you need to be careful to avoid concurrency violations.
Type Parameters
S
The type of the user defined actor state.M
The message types the actor accepts, usually Any.
It is rare to set M
, but if it is set then it should include at least Leave!
.
Actors.Actor
— MethodCreate an Actor with the given state and minder
Actors.AsyncFail!
— TypeInforms that an asynchronous Task
failed
Members
async::Task
What failed
Actors.Died!
— TypeInforms that an Actor
died
Members
who::Id
The
Actor
who diedcorpse::Actors.Actor
The
Actor
who died's data
Actors.Genesis!
— TypeSent to the users 'play' Actor
to get things started
Members
Actors.Id
— TypeThe Address of an Actor
This is a safe reference to an Actor
. It is most commonly used to send messages to an Actor
. However many accessor methods take an Addr
to safely get or set some Actor
's internals or associated data.
This will grow in size as remote actors are added.
Type Parameters
S
The type of the actor state.M
The message types the actor accepts, usually Any.
Actors.Invite!
— TypeActors.Invited!
— TypeA response to Invite!
Actors.Leave!
— TypeActors.Left!
— TypeActors.Logger
— TypeAn Actor
which prints messages to an IO
stream
By default one of these is created which writes to stdout exlusively.
Actors.PreGenesis!
— TypeUsed by the Stage
for bootstraping
Actors.Scene
— TypeThe context of message processing
Contains common information which is used by many different methods during message handling. You should assume that the members of this struct are likely to change.
Type Parameters
Actors.Shout!
— TypeWraps a message to broadcast (shout
)
Actors.Stage
— TypeThe Root Actor
This contains the addresses for all the actors and bootstraps the play
. Currently all actors are created by sending messages to the Stage
although this will probably change in the future.
Any messages which the Stage
can not handle, it forwards to the play
.
The Stage
bootstraps itself by putting the PreGenesis!
message in its inbox
. It processes this message first then sends Genesis!
to the actor specified by play!
.
It is unusual for the user to access this directly or override its behaviour. Most things can be achieved by creating a new AbsMinder
type or allowing messages to be forwarded to the Play actor.
Members
actors::Actors.AddressBook
All the
Actor
s in the playtime_to_leave::Union{Nothing, Timer}
Grace period timer before force leaving
play::Id
User defined play
Actor
Actors.Stooge
— TypeActors.TreeMinder
— TypeOrganises actors into a hieracy or tree structure. This is used as the default AbsMinder
for the play.
When an actor with this minder uses invite!
the returned actor will be a child of the current actor (the current actor being the parent). An actor may have many children, but only a single parent.
If a child actor dies then the parent recieves
Died!
. By default actors don't know how to handle this so they will also die. (In any case the death will be logged).If a parent leaves or dies, then its children are also asked to
Leave!
.
If you don't wish for an actor to die when one of its children do, then define hear
for the Died!
message.
Members
root::Id
minded::Union{Nothing, Id}
children::Set{Id}
Actors.Troupe
— TypeA group of Actor
's
Messages shout
ed at the Troupe
will be broadcast to the all the Actor
's in it. To send a message to the Troupe
itself, just use say
.
Example
Where a1..a3
are Actor
Id
's
g = enter!(s, Troupe(a1, a2, a3))
shout(s, g, Leave!())
say(s, g, Leave!())
Members
as::Array{Id,1}
The addresses of the
Actor
s in aTroupe
Actors.ask
— MethodActors.async
— MethodSimilar to @async
, but notifies the calling Actor
if it fails.
This allows you to create an asynchronous Task
without waiting on it to check for errors. If an exception is thrown, the Actor
will send AsyncFail!
to itself. By default this will cause TaskFailedException
to be thrown thus killing the Actor
.
Actors.capture_environment
— MethodUsed to capture variables from the parent thread/task
This is a workaround for integrating third party libraries which use Task local storage or similar. By default it does nothing and it is probably best to avoid using it. See enter!
and play!
.
Note that this is not necessary for getting OS "environment variables", which are typically shared amongst threads.
Actors.delegate
— MethodActors.dieing_breath!
— MethodActors.enter!
— MethodActors.epilogue!
— MethodActors.expect
— MethodWait for a message of type R
and return it
This will block waiting for a message of the right type. It will cause the Actor
to become 'insensitive', meaning that all other messages will be buffered while waiting.
When a message of the right type is recieved, then the buffered messages will be put back in the inbox
and the matching message is returned.
In theory this could accept the wrong message if the type matches, but it was from an old request or it was sent for some other reason. One way to avoid this is to delegate
the ask
request, or the entire operation, to a Stooge
which will have a new address.
Actors.fork
— MethodCreate a new Task, Thread or similar primitive
Actors.hear
— MethodHandle a received message
Usually called by listen!
to handle a message taken from the inbox
. The user defines new hear
methods to handle messages for different Actor
-message type combinations.
It is passed a Scene
object which has the Actor
state type as the first type parameter. By convention this argument is always called s
, if you use a different name it may break some non-essential macros. The other parameter is the message, which is usually called msg
, unless you have a more appropriate name, and can be of any type (in a local system).
If hear
returns a value it will most likely be ignored (unless you override listen!
). If you need to respond to a message then use say
or ask
.
Actors.inbox
— MethodGet the inbox of an Actor
Useful when overriding functions such as listen!
or leave!
. Otherwise it is quite unusual for the user to call this. You should use say
and ask
to send messages.
The inbox
is how an Actor
recieves messages. In a local system the sender directly places a message into the inbox
. Currently inboxes are implemented with a Julia Channel
which can be safely accessed by multiple threads, however it is generally expected that you don't pop!
messages from another actor's inbox unless that actor is dead.
Actors.interact!
— MethodLike play!
, but allows you to send and receive messages from the REPL
Calling this will asynchronously start a play
and return a 2-tuple of Scene
and Task
. The Scene
can be used to call various methods in the actor system and the task can be checked to see if the actor system has failed.
The function local_addresses
can be used to find out what Id
a given actor has.
This is only intended for interactive use in the Julia REPL or similar scenario.
Example
julia> using Actors
julia> struct Ponger end
julia> struct Echo
who::Id
msg::String
end
julia> Actors.hear(s::Scene{Ponger}, msg::Echo) = say(s, msg.who, msg.msg)
julia> (s, t) = interact!()
(Scene{Actors.Person}, Task (runnable) @0x00007fafc7dad600)
julia> me(s)
Actors.Person@1
julia> ponger = enter!(s, Ponger())
Ponger@5
julia> ask(s, ponger, Echo(me(s), "Echo, echo, ..."), String)
"Echo, echo, ..."
julia> local_addresses(s)
5-element Array{Pair{Int64,DataType},1}:
1 => Actors.Person
2 => Actors.Logger{Base.TTY}
3 => Actors.PassiveMinder{Id{Actors.Logger{Base.TTY},Union{Leave!, Actors.LogDied!, LogInfo!}}}
4 => Actors.InteractivePlay
5 => Ponger
Actors.interact!
— MethodStart a minimal actor system which you can interact with from the REPL
Actors.invite!
— MethodActors.leave!
— MethodSignal that the current Actor
should exit (leave)
Usually this closes the inbox
which will cause the actor to exit once it has processed any messages it already received. Some actors (e.g Stage
) have a grace period where they will continue to accept new messages.
If you wish to exit immediately then throw an exception.
Also see Leave!
.
Actors.listen!
— MethodTake messages from the inbox
and process them
By default this simply takes messages from the inbox
and calls hear
on them. However you may wish to process some messages specially or do some work inbetween messages, in which case you can override this for a given Actor
type.
As a general rule, you should make sure to call hear
on a message if you can't process it some other way. Otherwise you will prevent some standard messages from working (such as Leave!
).
Actors.local_addresses
— MethodActors.me
— MethodActors.minder
— MethodGet the address of an Actor
's minder
When called on the Scene
it will get the current Actor's minder. If called on an Id
it will get the minder of the Actor pointed to by the address.
It is generally not thread-safe to change Actor.minder
. However you can re-assign a minder's Id
to another actor.
See AbsMinder
.
Actors.my
— MethodActors.play!
— MethodStart the 'Actor System' or a single Actor
Typically the user calls this method on some value which is used as the 'play' Actor
state. This then blocks the calling thread until the Stage
is sent Leave!
or dies due to an error which was allowed to propagate.
This is also called by enter!
, in a new Thread/Task, to run a single Actor
. Nothing should happen before or after play!
so it contains the Actor
's full lifetime (excluding Julia internals).
The liftime of the Actor
looks something like:
Then, if there is an error
You can override any of the above, so if you are forced to override play!(s::Scene, env)
this is considered a library design error. Usually if you feel the need to override any of these, then you should solve the problem with AbsMinder
or more message passing instead.
Actors.prologue!
— MethodActors.say
— MethodSend a message asynchronously
This returns immediately and doesn't guarantee the message is processed by the actor specified by to
. Nor does it guarantee messages will be delivered in the order say
is called.
This may throw an error if, for example, to
only accepts certain message types.
This doesn't expect a response from to
. For that see ask
.
Actors.shout
— MethodBroadcast a message to a plain vector of actors
Actors.shout
— MethodBroadcast a message to a Troupe
Actors.stage
— MethodActors.try_say
— MethodLike say
, but less likely to throw an exception if to
is dead. This is commonly useful when an unexpected error has occurred and you want to perform some cleanup without knowing which actors are still alive. Under normal operation you should expect other actors to be alive if you are sending them a message.
If, for example, to
exceeds the highest known ID in the local Stage
then this will still throw a BoundsError
. This is to help prevent silent errors.
Actors.@say_info
— Macro