Application View

The application view covers Actors and Messages and how functional components are used.

Sodacan Supports Business Processes

From a design perspective, actors provide a way to represent steps in a business process without having to worry about data persistence: If an Actor “owns” some data, that data stays with the Actor. Sodacan supports “foreign data” as well: An Actor can maintain a copy of data that is owned by another Actor. Any updates to the owning Actor's data arrives in a message. The foreign data can arrive before a business event message or after. It can't arrive during an event. However, it can arrive “with” the business event. For example, a message starting out with just a customer id in its payload could be routed through the customer Actor to pick up a subset of customer data needed to complete the transaction in the target Actor. When the message arrives at, for example, a shopping-cart actor, the customer information is available in the payload. In Sodacan, this is called message routing which allows a single message to represent a business transaction with several steps. In addition to simple point-to-point messages, it is also common for messages that represent a business processes to fan-out and fan-in to easily allow parallel processing. In a shopping-cart example, a message would fan-out to all of the product actors for a price quote and then fan-in to complete the flow.

Each Sodacan Actor has a stage which holds zero or more outbound messages. The Stage, and hence its name, holds all external effects from processing one inbound message. This includes the Actor's persistent data. The Actor's Stage is what supports transaction semantics. The messages in the stage will be sent upon a commit within the Actor, or rolled back as needed.

Actors

A small island of compute sending and receiving messages to/from other Actors. Let's get started:

Message Processing

An Actor executes in a single thread of execution. Messages for a given Actor line up in a queue and are processed one at a time. When not processing a message, the actor and its state can cease to exist as long as when the next message is ready to process the Actor has the same state as it left behind since the last message was processed. This process is handled by Sodacan, the Actor just needs to implement the ‘Actor.processMessage()’ method.

Routing Stack

The Stage

Actor Lifecycle

An actor has an interesting lifecycle: Starting with an actor that needs to “create” another actor. For example, say a shopping cart Actor needs to create a new Invoice actor. In Sodacan, one actor cannot have direct access to another Actor, this includes creating another Actor. An Actor does not own another Actor. So, how does an Actor create another Actor? Sodacan solves this problem with a simple rule: If an Actor puts together a valid ActorId, then sending a message to that ActorId is enough for the Actor to exist. Now, you might be thinking that doing so leads to trouble. And that would be true but for two features. First, the ActorId has to be valid which means the type of Actor has to be know (registered). Second, the ActorGroup number has to be valid. The interesting part is the Id itself. And there's two ways to create the Id part of an ActorId: The easiest is to let Sodacan generate the Id. Sodacan puts together an ActorId that is unique. The other approach is to carry some business identifier such as employee id, shopping cart id, etc. The second approach is discouraged.

Once the new ActorId is known, the creating Actor is able to store the ActorId so that it can be accessed later. Also, the creating Actor or any other Actor is free to send Messages to that new Actor.

Usually, a Message will flow through one or more Actors that translate from a business Id, such as Employee Id into an ActorId. See Collections below.

Actor as a State Machine

When processing a message, an Actor has two two bits of information: the message, specifically, the “Verb” of the message. This is the “ask”; The event. The other is the current state of the actor: How things stand with the actor. Together, these identify the transitions within a State Machine.

Host Bound Actors

A host bound actor enjoys a different lifecycle from normal actor. This type of Actor is commonly used for device interfaces, network connections, or other functions that require access to the specific that they run on.

An Actor that implements the HostBound interface will be treated as a Host-bound Actor. Such Actors have a slightly different lifecycle:

The Actor will be created immediately when a Host starts up. (Normal Actors are not instantiated until they receive their first message.) The Actor will not be closed until a specific handshake occurs. (Normal actors can be removed from memory at any time, that is, between messages.) The Host-bound actor will receive an initial Builtin.Start message. This alerts the Actor to open connections or other system resources, as needed. Host-bound Actors can send and receive messages just like normal Actors. When a Host is ready to shut down, it first asks any HostBound Actors to close by calling a close method on the Actor. This process blocks until all HostBound actors have returned from the close method. The Host can then complete its shutdown process.

A normal Actor acts in a simple call-return protocol: Sodacan calls processMessage with an inbound message. The Actor does something and populates the Stage in response to that inbound message. However, it would be common for a Host-bound Actor to perform some asynchronous IO operations. That doesn't change for Host-bound Actors. All actors must remain responsive to processMessage calls. If a Host-bound Actor is, for example, an HTTP server, it will also need to hand new messages to Sodacan asynchronously. In that case, a different method is available to an Actor: send(Message). It will deliver messages outside the main processMessage loop. Naturally the Actor will need to be more careful because it might be working in two or more threads at the same time! At least the send method is thread safe relative the Actor.