Documentation / Foundations

Actors and commands

Troolio uses Microsoft Orleans actors as the command boundary. An actor interface extends IActor; a concrete actor handles typed messages and keeps the current state derived from its event history. CqrsActor, EventSourcedActor, StatefulActor, ProjectionActor, and OrchestrationActor serve different roles rather than interchangeable base classes.

On this page

Command path

A Command<TActor> addresses a specific actor contract. A handler named Handle returns zero or more domain events. The actor dispatches those events to On handlers to update its in-memory state. Queries use Query<TActor,TResult> and a typed handler to read that current state. The first actor guide has a compiled example.

InternalCommand<TActor> is used for framework and orchestration work inside the actor system. A serving host still has to decide which external commands it permits, authenticate the caller, and authorize the target. Message Metadata carries correlation and identity fields; it is trace context, not proof of current authorization.

Actor roles

Role Typical responsibility
Event sourced actor Replays a stream, handles commands, emits events, and answers queries.
Stateful actor Maintains state from subscribed events for internal orchestration.
Projection actor Consumes events to update a read model outside the command transaction.
Orchestration actor Reacts to events and may issue internal commands.
Dispatch actor Provides typed message dispatch without selecting a persistence policy.

Ordinary and selected command paths

The ordinary actor path appends to its configured store and dispatches events according to host configuration. A separately selected atomic path plans a closed participant set and requires a capable transaction store, route authority, and completion receipt. Do not infer selected-route guarantees from an ordinary Command call. Read selected command route before using it.

Design checks

Example: Send a typed command

Using the counter actor from the first actor guide, a client addresses one actor ID and sends its command. The host still authorizes the caller and target.

public static Task Send(ITroolioClient client, Metadata headers) =>
    client.Tell<ICounterActor>("42", new Increment(headers));

Choosing a real application boundary

Use actor boundaries and identity to place invariants and stable keys, then follow CQRS in practice to choose between actor queries and semantic SQL views.