Aggregate Root Actor
Aggregate Root Actor is responsible for running the Aggregate Root state machine (the AR behavior). It is a Persistent Actor. When a Command Messages comes in, the actor invokes the current Command Handler (the Command Handler associated with the current state) and if the command is accepted, appends the Event Message(s) to the actor’s journal. Once the event message(s) is persisted, the AR actor invokes the current Event Handler (the Event Handler associated with the current state) and the AR transitions to the next state.
Aggregate Root Actors are not directly accessible by the clients. They are like clerks working in an office. The only way to perform an operation on a particular Aggregate Root (a business entity / case) is to submit a form (command) to the respective Office.
Aggregate Root Actor Factory
Aggregate Root Actor Factory should provide a recipe (Props) for the Aggregate Root Actor of specified class. The supervising Office will use that recipe to create the actor. Please see an example of the AR Actor Factory below:
implicit object ReservationARFactory extends AggregateRootActorFactory[Reservation] {
def props(pc: PassivationConfig) = Props(new Reservation(DefaultConfig(pc)))
}
See also: Aggregate Root Configuration
Office
The office should publish its identifier to be used across the system by the service consumers and client applications. The office identifier should allow obtaining the identifier of the office journal and the identifiers of the journals of the individual business entities (cases).
Akka-DDD provides the [RemoteOfficeId] class to be used for that purpose.
The identifier of the sample Reservation office is shown below:
RemoteOfficeId(
id = "Reservation",
department = "Sales",
messageClass = classOf[sales.Command]
)
The messageClass property defines the base class of all message classes that the office is ready to handle (this information helps to auto-configure the command dispatching that is performed by the write-front application).
Office creation
val reservationOffice = OfficeFactory.office[Reservation]
Assuming the newicom.dddd.cluster
package object is available in the scope (the package object is imported), the actual office creation is delegated to the cluster-aware / sharding-capable OfficeFactory object that is injected automatically as an implicit argument of the office
method. The office factory requires an AR Actor Factory
and a shard allocation strategy to be implicitly provided for the given AR Actor class. The Office
object that is eventually created contains the office identifier and the address (in the form of an ActorPath) of the office representative Actor.
Graceful Passivation
To reduce memory consumption, idle Aggregate Root Actors should be passivated (removed from the memory) after a specified inactivity timeout. To do it safely AR Actor is configured to receive ReceiveTimeout after specified inactivity period. Being notified, AR Actor asks the Office to dismiss him gracefully. The pattern/protocol is called Graceful Passivation and is supported by the Akka-DDD (see GracefulPassivation trait).
See also: Passivation Configuration
Collaboration with other Actors
The example of collaboration implementation can be found in the DummyAggregateRoot Actor:
class DummyAggregateRoot(cfg: DummyConfig)
extends AggregateRoot[DummyEvent, Dummy, DummyAggregateRoot]
with AggregateRootLogger[DummyEvent]
with ConfigClass[DummyConfig] {
val config: DummyConfig = cfg.copy(valueGeneration = valueGeneration)
lazy val valueGeneratorActor: ActorRef = context.actorOf(ValueGeneratorActor.props(cfg.valueGenerator))
private def valueGeneration: Collaboration = {
implicit val timeout = 10.millis
(valueGeneratorActor !< GenerateRandom) {
case ValueGeneratorActor.ValueGenerated(value) =>
state.rejectNegative(value) orElse
ValueGenerated(id, value, confirmationToken = uuidObj) match {
case Reject(_) => valueGeneration
case r => r
}
}
}
}
ValueGeneratorActor is some other actor responsible for generating a random value in response to the GenerateRandom
message. The Dummy Aggregate Root Actor needs to implement the interaction with the ValueGeneratorActor as a Collaboration
type and expose it via the Aggregate Root Configuration interface. Collaboration
is a special subtype of the Reaction
type. See Aggregate Root Implementation - Command Handling for more information about the Reaction
.