Reference
CircoCore.Actor
CircoCore.ActorId
CircoCore.Addr
CircoCore.CircoContext
CircoCore.EventSource
CircoCore.EventSourceDied
CircoCore.Failure
CircoCore.OnBecome
CircoCore.OnDeath
CircoCore.OnSpawn
CircoCore.Pos
CircoCore.PostCode
CircoCore.SigTerm
CircoCore.Subscribe
CircoCore.Tokenized
CircoCore.UnSubscribe
Circo.onmigrate
CircoCore.addr
CircoCore.addr
CircoCore.become
CircoCore.box
CircoCore.box
CircoCore.die
CircoCore.fire
CircoCore.getname
CircoCore.isbaseaddress
CircoCore.isnulladdr
CircoCore.onmessage
CircoCore.pos
CircoCore.redirect
CircoCore.registername
CircoCore.send
CircoCore.spawn
CircoCore.traits
Items from CircoCore are reexported thus available directly from Circo.
CircoCore.Actor
— Typeabstract type Actor{TCoreState}
Supertype of all actors.
Subtypes must be mutable and must provide a field core::TCoreState
that can remain undefined after creation.
Examples
mutable struct DataHolder{TValue, TCore} <: Actor{TCore}
value::TValue
core::TCore
end
CircoCore.ActorId
— TypeActorId
A cluster-unique id that is randomly generated when the actor is spawned (first scheduled).
ActorId
is an alias to UInt64
at the time, so it may pop up in error messages as such.
CircoCore.Addr
— TypeAddr(postcode::PostCode, box::ActorId)
Addr(readable_address::String)
Addr()
The full address of an actor.
When created without arguments, it will be the null address. See isnulladdr()
If the referenced actor migrates to a different scheduler, messages sent to the old address will bounce back as RecipientMoved
and the Addr must be updated manually.
Examples
Addr("192.168.1.11:24721", 0xbc6ac81fc7e4ea2)
Addr("192.168.1.11:24721/bc6ac81fc7e4ea2")
CircoCore.CircoContext
— TypeCircoContext(;options...) <: AbstractContext
Store configuration, manage staging and run-time code optimizations for Circo.
CircoCore.EventSource
— TypeEventSource
Trait for actors that can publish events.
Manages subscriptions and dispatches events. You need to add a field eventdispatcher::Addr
to your actor to use this trait.
CircoCore.EventSourceDied
— TypeEventSourceDied
SigTerm cause for terminating event dispatchers.
CircoCore.Failure
— Typeabstract type Failure <: Response end
Failure
is a type of Response
to a Request
that fails to fulfill it.
CircoCore.OnBecome
— TypeOnBecome(reincarnation::Actor)
Actor lifecycle message marking the become()
action.
reincarnation
points to the new incarnation of the actor. me
is scheduled at the delivery time of this message, reincarnation
is not.
Exceptions thrown while handling OnBecome
will propagate to the initiating
become` call.
CircoCore.OnDeath
— TypeOnDeath
Actor lifecycle message to release resources when the actor dies (meaning unscheduled "permanently").
The actor is still scheduled when this message is delivered, but no more messages will be delivered after this.
CircoCore.OnSpawn
— TypeOnSpawn
Actor lifecycle message that marks the first scheduling of the actor, sent during spawning, before any other message.
Examples
CircoCore.onmessage(me::MyActor, ::OnSpawn, service) = begin
registername(service, "MyActor", me) # Register this actor in the local name service
end
CircoCore.Pos
— TypePos(x::Real, y::Real, z::Real)
Pos(coords)
A point in the 3D "actor space".
You can access the coords by pos.x, pos.y, pos.z.
CircoCore.PostCode
— TypePostCode
A string that identifies a scheduler.
Examples
"192.168.1.11:24721"
CircoCore.SigTerm
— TypeSigTerm(cause=Nothing; exit=Nothing)
Signal to terminate an actor.
The default handler terminates the actor without delay.
CircoCore.Subscribe
— TypeSubscribe(eventtype::Type, subscriber::Union{Actor, Addr}, filter::Union{Nothing, String, Function} = nothing)
Message for subscribing to events of the given eventtype
.
The subscription can be optionally filtered by a topic string or a predicate function. Filtering and subscription management will be done by the event dispatcher, which is a separate actor.
eventtype
must be concrete.
Examples
fs = getname(service, "fs")
send(service, me, fs, Subscribe(FSEvent, me, "MODIFY"))
send(service, me, fs, Subscribe(FSEvent, me, event -> event.path == "test.txt"))
CircoCore.Tokenized
— TypeCircoCore.UnSubscribe
— TypeUnsubscribe(subscriber::Addr, eventtype::Type)
Message for unsubscribing from events of the given eventtype
.
Cancels all subscriptions of the given subscriber
for the given eventtype
.
CircoCore.addr
— Methodaddr(a::Actor)
Return the address of the actor.
Call this on a spawned actor to get its address. Throws UndefRefError
if the actor is not spawned.
CircoCore.addr
— Methodaddr(entity)
Return the address of entity.
The default implementation returns the addr
field, allowing you to use your own structs with such fields as message targets.
CircoCore.become
— Methodbecome(service, old::Actor, reincarnated::Actor)
Reincarnates the old
actor into new
, meaning that old
will be unscheduled, and reincarnated
will be scheduled reusing the address of old
.
The onbecome
lifecycle callback will be called.
Note: As the name suggests, become
is the Circonian way of behavior change.
CircoCore.box
— Methodbox(a::Actor)
Return the 'P.O. box' of the spawned actor.
Call this on a spawned actor to get its id (aka box). Throws UndefRefError
if the actor is not spawned.
CircoCore.box
— Methodbox(a::Addr)::ActorId
Return the box of the address, that is the id of the actor.
When the actor migrates, its box remains the same, only the PostCode of the address changes.
CircoCore.die
— Methoddie(service, me::Actor; exit=false)
Permanently unschedule the actor from its current scheduler.
if exit
is true and this is the last actor on its scheduler, the scheduler will be terminated.
CircoCore.fire
— Methodfire(service, me::Actor, event::Event)
Fire an event on the actor to be delivered by the actor's eventdispatcher.
To fire an event, the actor must have a field eventdispatcher::Addr
, which will be filled automatically.
CircoCore.getname
— Methodfunction getname(service, name::String)::Union{Addr, Nothing}
Return the registered name from the scheduler-local registry, or nothing.
See also: NameQuery
CircoCore.isbaseaddress
— Methodisbaseaddress(addr::Addr)::Bool
Return true if addr
is a base address, meaning it references a scheduler directly.
CircoCore.isnulladdr
— Methodisnulladdr(a::Addr)
Check if the given address is a null address, meaning that it points to "nowhere", messages sent to it will be dropped.
CircoCore.onmessage
— Methodonmessage(me::Actor, message, service)
Actor callback to handle a message arriving at an actor.
Only the payload of the message is delivered, there is currently no way to access the infoton or the sender address. If you need a reply, include the sender address in the request.
Note: Do not forget to import it or use its qualified name to allow overloading!
Examples
import CircoCore.onmessage
struct TestRequest
replyto::Addr
end
struct TestResponse end
function onmessage(me::MyActor, message::TestRequest, service)
send(service, me, message.replyto, TestResponse())
end
CircoCore.pos
— Methodpos(a::Actor)::Pos
return the current position of the actor.
Call this on a spawned actor to get its position. Throws UndefRefError
if the actor is not spawned.
CircoCore.redirect
— Methodredirect(addr::Addr, topostcode::PostCode):Addr
Create a new Addr by replacing the postcode of the given one.
CircoCore.registername
— Methodregistername(service, name::String, actor::Union{Addr,Actor})
Register the given actor under the given name in the scheduler-local name registry.
Note that there is no need to unregister the name when migrating or dying
TODO implement manual and auto-unregistration
CircoCore.send
— Methodsend(service, sender::Actor, to::Addr, messagebody::Any; energy::Real = 1, timeout::Real = 2.0)
Send a message from an actor to an another.
Part of the actor API, can be called from a lifecycle callback, providing the service
you got.
messagebody
can be of any type, but a current limitation of inter-node communication is that the serialized form of messagebody
must fit in an IPv4 UDP packet with ~100 bytes margin. The exact value depends on the MTU size of the network and changing implementation details, but 1380 bytes can be considered safe. You may be able to tune your system to get higher values.
If messagebody
is a Request
, a timeout will be set for the token of it. The timeout
keyword argument can be used to control the deadline (seconds).
energy
sets the energy and sign of the Infoton attached to the message (if the infoton optimizer is running).
Examples
const QUERY = "The Ultimate Question of Life, The Universe, and Everything."
mutable struct MyActor <: Actor{TCoreState}
searcher::Addr
core::CoreState
MyActor() = new()
end
struct Start end
struct Search
query::String
end
[...] # Spawn the searcher or receive its address
function CircoCore.onmessage(me::MyActor, message::Start, service)
send(service,
me,
me.searcher,
Search(QUERY, addr(me)))
end
Implementation
Please note that service
is always the last argument of lifecycle callbacks like onmessage
. It's because onmessage
is dynamically dispatched, and service
provides no information about where to dispatch. (Only one service instance exists as of v"0.2.0"
) Listing it at the end improves performance.
On the other hand, actor API endpoints like send
are always statically dispatched, thus they can accept the service as their first argument, allowing the user to treat e.g. "spawn(service
" as a single unit of thought and not forget to write out the ballast service
.
Consistency is just as important as convenience. But performance is king.
CircoCore.spawn
— Methodspawn(service, actor::Actor, [pos::Pos])::Addr
Spawn the given actor on the scheduler represented by service
, return the address of it.
Part of the actor API, can be called from a lifecycle callback, providing the service
you got.
The OnSpawn
message will be delivered to actor
before this function returns.
Examples
TODO: update this sample
mutable struct ListItem{TData, TCore} <: Actor{TCore}
data::TData
next::Union{Nothing, Addr}
core::TCore
ListItem(data, core) = new{typeof(data), typeof(core)}(data, nothing, core)
end
struct Append{TData}
value::TData
end
function CircoCore.onmessage(me::ListItem, message::Append, service)
me.next = spawn(service, ListItem(message.value))
end
CircoCore.traits
— Methodtraits(::Type{<:Actor}) = ()
You can declare the traits of an actor by defining a method of this function.
Traits can handle messages in the name of the actor, helping to compose the behavior of the actor (See ontraitmessage()
.).
E.g.: The EventSource trait handles the Subscribe and UnSubscribe messages automatically (among others). Anything can be a trait, but we recommend to use immutable structs.
Return a tuple of traits, either instantiated or not. Instantiated traits can hold values, while traits given as types will be instantiated without arguments.
Important: Traits cannot hold state. If a trait needs to store state in the actor you have to add fields to the actor manually.
Examples
struct DumpFieldTrait # Dumps a single field of the actor to stdout when the actor is dying. fieldname::Symbol end
CircoCore.ontraitmessage(trait::DumpFieldTrait, me, ::OnDeath, service) = begin println("¨trait.fieldname: getfield(me, trait.fieldname)") end
mutable struct MyActor <: Actor{Any} a b core MyActor() = new(rand(Int8), rand(Int8)) end
CircoCore.traits(::Type{MyActor}) = (DumpFieldTrait(:a), DumpFieldTrait(:b))
Circo.onmigrate
— Methodonmigrate(me::Actor, service)
Lifecycle callback that marks a successful migration.
It is called on the target scheduler, before any messages will be delivered.
Note: Do not forget to import it or use its qualified name to allow overloading!
Examples
function Circo.onmigrate(me::MyActor, service)
@info "Successfully migrated, registering a name on the new scheduler"
registername(service, "MyActor", me)
end