Actor system
In an actor application, an actor is the fundamental unit of computation. It’s the thing that receives a message and does some computation based on it. The idea is very similar to what we have in object-oriented languages: an object receives a method call and does something depending on which method was called.
The main differences are that actors:
- Are entirely isolated from each other, sharing no resources (memory or otherwise). An actor maintains a private state that may never be mutated directly by another entity.
- Own their execution context. In contrast with a method call performed on an object, the calling thread will not enter the actor; instead, the actor shall eventually perform the requested action. This allows actor application to run lock-free.
In a nutshell, Actors are named because they act by themselves, in contrast with objects that are just resources acted upon by threads. Akka, a JVM-based actor framework has an excellent primer on the actor model, it is available here.
Difference with other implementations
Ultramarine differs from other actor system implementations in a few key points:
- Messages are expressed as
futures
. There are no one-way messages in Ultramarine, and all message handler can return results. - Virtual actors are completely horizontal. Error propagation method choice is left to the developer (
exception
,optional
,expected
, etc.) - Messages are not objects. Unlike in Erlang or Akka, messages in Ultramarine are simple function calls with optional arguments.
- Actors do not have individual mailboxes. Ultramarine does not assign mailboxes to actors for various reasons. Rather, each execution unit (reactor thread) have a single task queue in which messages are scheduled.
- Actors cooperate, rather than being preempted. Blocking in actor code is, therefore, a big no-no. Fortunately, Seastar provides lots of nice constructs to help with this.