In Akka, how do I know when an actor is ready to use after having been registered with actorOf()? - actor

If I create an actor using context().actorOf() in Akka, I get back a valid ActorRef. However, if I do the same but create an ActorRef using actorFor and the path I know that the actor will appear at, I do not reliably get a valid ActorRef back. How can I tell that an actor has been registered successfully?
In the description above, I could simply use the ActorRef returned from actorOf(). However, in my actual case I create an actor that itself registers a child actor and I need to resolve that, so the problem in general is "how can I wait / register to be informed of an actor having been registered at a known path?".

Since Akka 2.2.1 you can use ActorSelection.resolveOne to get an ActorRef from an actor selection:
implicit val timeout = Timeout(5, TimeUnit.SECONDS)
val selection = system.actorSelection("/user/myActor")
val actor = Await.result(selection.resolveOne(), timeout.duration)
From the docs http://doc.akka.io/api/akka/2.2.1/index.html#akka.actor.ActorSelection
Resolve the ActorRef matching this selection. The result is returned
as a Future that is completed with the ActorRef if such an actor
exists. It is completed with failure ActorNotFound if no such actor
exists or the identification didn't complete within the supplied
timeout.
Under the hood it talks to the actor to verify its existence and
acquire its ActorRef.

First of all, there's no guarantee that the ActorRef you get back from actorOf is still alive, since the constructor of it could have failed.
Secondly, actorFor might find the actor but it died just after being found and just before you started working with it.
Thirdly, it's normally good practice to structure your application so that dependencies are propagated in a logical fashion, so that there is a natural rendez-vous point between your actors.
Hope any of the above helps,
happy hAkking!
√

Related

Issue with Synchronisation of Agents from different types in a shared discrete space projection

I have an issue regarding the synchronisation of different agents.
So I have a shared context with a BaseAgent class as the tutorial suggested for the case where we have more than 1 agent type in the same context. Then I have 4 more agent classes which are children of the Base Agent Class. For each of them I have the necessary serialisable agent packages and in my model class I also have specific package receivers and providers for each one of them.
All those agents are sharing a discrete spatial projection of the form:
repast::SharedDiscreteSpace<BaseAgentClass, repast::WrapAroundBorders, repast::SimpleAdder< BaseAgentClass > >* discreteSpace;
Three of my 4 agent types can move around and I have implemented their moves. However, they can move from one process to another and I need to use the 4 synchronisation statements which were introduced in the RepastHPC tutorial HPC:D03, Step 02: Agents Moving in Space.
The thing however is that I am not certain how to actually synchronise them, since the agents would need their specific providers, receivers and serialisable packages in order to be copied into the other process correctly. I tried doing the following:
discreteGridSpace->balance();
repast::RepastProcess::instance()->synchronizeAgentStatus<BaseAgentClass, SpecificAgentPackage, SpecificAgentPackageProvider, SpecificAgentPackageReceiver>(context, *specificAgentProvider, *specificAgentProvider, *specificAgentReceiver);
repast::RepastProcess::instance()->synchronizeProjectionInfo<BaseAgentClass, SpecificAgentPackage, SpecificAgentPackageProvider, SpecificAgentPackageReceiver>(context, *specificAgentProvider, *specificAgentProvider, *specificAgentReceiver);
repast::RepastProcess::instance()->synchronizeAgentStates< SpecificAgentPackage, SpecificAgentPackageProvider, SpecificAgentPackageReceiver >(* specificAgentProvider, * specificAgentReceiver);
However, when running I get the following error:
===================================================================================
= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
= PID 3224 RUNNING AT Aleksandars-MBP
= EXIT CODE: 11
= CLEANING UP REMAINING PROCESSES
= YOU CAN IGNORE THE BELOW CLEANUP MESSAGES
===================================================================================
YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault: 11 (signal 11)
This typically refers to a problem with your application.
Please see the FAQ page for debugging suggestions
So I am not certain how to actually synchronise the agents for each specific agent type, since they are all sharing the same context and spatial projection with the BaseAgentClass.
Thank you for the help in advance!
The intention here is that you'd have a single package that can be used for all the agent types. For example, in the Zombies demo model, the package has entries for the agent id components, and also infected and infectionTime. These last two only apply to the Human agents and not to the Zombies.
The methods where you provide and receive content should check for the agent type and take the appropriate action. For example, in the Zombies Model we have
void ZombieObserver::provideContent(RelogoAgent* agent, std::vector<AgentPackage>& out) {
AgentId id = agent->getId();
AgentPackage content = { id.id(), id.startingRank(), id.agentType(), id.currentRank(), 0, false };
if (id.agentType() == humanType) {
Human* human = static_cast<Human*> (agent);
content.infected = human->infected();
content.infectionTime = human->infectionTime();
}
out.push_back(content);
}
Here you can see we fill the AgentPackage with some defaults for infected and infectionTime and then update those if the agent is of the Human type. This is a ReLogo style model, so some of the details might be different but hopefully it's clear that there is a single package type that can handle all the agent types, and that you use the agent type to distinguish between types in your provide methods.

How can I write a save GUI-Aktor for Scalafx?

Basically I want an Aktor to change a scalafx-GUI safely.
I've read many posts describing this, but there where sometimes contradictory and some years old, so some of them might be outdated.
I have a working example code and I basically want to know if this kind of programming is thread-save.
The other question is if I can configure sbt or the compiler or something in a way, that all threads (from the gui, the actors and the futures) are started by the same dispatcher.
I've found some example code "scalafx-akka-demo" on GitHub, which is 4 years old. What I did in the following example is basically the same, just a little simplified to keep things easy.
Then there is the scalatrix-example approximately with the same age. This example really worries me.
In there is a self-written dispatcher from Viktor Klang from 2012, and I have no idea how to make this work or if I really need it. The question is: Is this dispatcher only an optimisation or do I have to use something like it to be thread save?
But even if I don't absolutely need the dispatcher like in scalatrix, it is not optimal to have a dispatcher for the aktor-threads and one for the scalafx-event-threads. (And maybe one for the Futures-threads as well?)
In my actual project, I have some measurement values coming from a device over TCP-IP, going to an TCP-IP actor and are to be displayed in a scalafx-GUI. But this is much to long.
So here is my example code:
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import scala.concurrent.{Await, Future}
import scala.concurrent.duration._
import scalafx.Includes._
import scalafx.application.{JFXApp, Platform}
import scalafx.application.JFXApp.PrimaryStage
import scalafx.event.ActionEvent
import scalafx.scene.Scene
import scalafx.scene.control.Button
import scalafx.stage.WindowEvent
import scala.concurrent.ExecutionContext.Implicits.global
object Main extends JFXApp {
case object Count
case object StopCounter
case object CounterReset
val aktorSystem: ActorSystem = ActorSystem("My-Aktor-system") // Create actor context
val guiActor: ActorRef = aktorSystem.actorOf(Props(new GUIActor), "guiActor") // Create GUI actor
val button: Button = new Button(text = "0") {
onAction = (_: ActionEvent) => guiActor ! Count
}
val someComputation = Future {
Thread.sleep(10000)
println("Doing counter reset")
guiActor ! CounterReset
Platform.runLater(button.text = "0")
}
class GUIActor extends Actor {
def receive: Receive = counter(1)
def counter(n: Int): Receive = {
case Count =>
Platform.runLater(button.text = n.toString)
println("The count is: " + n)
context.become(counter(n + 1))
case CounterReset => context.become(counter(1))
case StopCounter => context.system.terminate()
}
}
stage = new PrimaryStage {
scene = new Scene {
root = button
}
onCloseRequest = (_: WindowEvent) => {
guiActor ! StopCounter
Await.ready(aktorSystem.whenTerminated, 5.seconds)
Platform.exit()
}
}
}
So this code brings up a button, and every time it is clicked the number of the button increases. After some time the number on the button is reset once.
In this example-code I tried to bring the scalafx-GUI, the actor and the Future to influence each other. So the button click sends a message to the actor, and then the actor changes the gui - which is what I am testing here.
The Future also sends to the actor and changes the gui.
So far, this example works and I haven't found everything wrong with it.
But unfortunately, when it comes to thread-safety this doesn't mean much
My concrete questions are:
Is the method to change the gui in the example code thread save?
Is there may be a better way to do it?
Can the different threads be started from the same dispatcher?
(if yes, then how?)
To address your questions:
1) Is the method to change the gui in the example code thread save?
Yes.
JavaFX, which ScalaFX sits upon, implements thread safety by insisting that all GUI interactions take place upon the JavaFX Application Thread (JAT), which is created during JavaFX initialization (ScalaFX takes care of this for you). Any code running on a different thread that interacts with JavaFX/ScalaFX will result in an error.
You are ensuring that your GUI code executes on the JAT by passing interacting code via the Platform.runLater method, which evaluates its arguments on the JAT. Because arguments are passed by name, they are not evaluated on the calling thread.
So, as far as JavaFX is concerned, your code is thread safe.
However, potential issues can still arise if the code you pass to Platform.runLater contains any references to mutable state maintained on other threads.
You have two calls to Platform.runLater. In the first of these (button.text = "0"), the only mutable state (button.text) belongs to JavaFX, which will be examined and modified on the JAT, so you're good.
In the second call (button.text = n.toString), you're passing the same JavaFX mutable state (button.text). But you're also passing a reference to n, which belongs to the GUIActor thread. However, this value is immutable, and so there are no threading issues from looking at its value. (The count is maintained by the Akka GUIActor class's context, and the only interactions that change the count come through Akka's message handling mechanism, which is guaranteed to be thread safe.)
That said, there is one potential issue here: the Future both resets the count (which will occur on the GUIActor thread) as well as setting the text to "0" (which will occur on the JAT). Consequently, it's possible that these two actions will occur in an unexpected order, such as button's text being changed to "0" before the count is actually reset. If this occurs simultaneously with the user clicking the button, you'll get a race condition and it's conceivable that the displayed value may end up not matching the current count.
2) Is there may be a better way to do it?
There's always a better way! ;-)
To be honest, given this small example, there's not a lot of further improvement to be made.
I would try to keep all of the interaction with the GUI inside either GUIActor, or the Main object to simplify the threading and synchronization issues.
For example, going back to the last point in the previous answer, rather than have the Future update button.text, it would be better if that was done as part of the CounterReset message handler in GUIActor, which then guarantees that the counter and button appearance are synchronized correctly (or, at least, that they're always updated in the same order), with the displayed value guaranteed to match the count.
If your GUIActor class is handling a lot of interaction with the GUI, then you could have it execute all of its code on the JAT (I think this was the purpose of Viktor Klang's example), which would simplify a lot of its code. For example, you would not have to call Platform.runLater to interact with the GUI. The downside is that you then cannot perform processing in parallel with the GUI, which might slow down its performance and responsiveness as a result.
3) Can the different threads be started from the same dispatcher? (if yes, then how?)
You can specify custom execution contexts for both futures and Akka actors to get better control of their threads and dispatching. However, given Donald Knuth's observation that "premature optimization is the root of all evil", there's no evidence that this would provide you with any benefits whatsoever, and your code would become significantly more complicated as a result.
As far as I'm aware, you can't change the execution context for JavaFX/ScalaFX, since JAT creation must be finely controlled in order to guarantee thread safety. But I could be wrong.
In any case, the overhead of having different dispatchers is not going to be high. One of the reasons for using futures and actors is that they will take care of these issues for you by default. Unless you have a good reason to do otherwise, I would use the defaults.

Closing over java.util.concurrent.ConcurrentHashMap inside a Future of Actor's receive method?

I've an actor where I want to store my mutable state inside a map.
Clients can send Get(key:String) and Put(key:String,value:String) messages to this actor.
I'm considering the following options.
Don't use futures inside the Actor's receive method. In this may have a negative impact on both latency as well as throughput in case I've a large number of gets/puts because all operations will be performed in order.
Use java.util.concurrent.ConcurrentHashMap and then invoke the gets and puts inside a Future.
Given that java.util.concurrent.ConcurrentHashMap is thread-safe and providers finer level of granularity, I was wondering if it is still a problem to close over the concurrentHashMap inside a Future created for each put and get.
I'm aware of the fact that it's a really bad idea to close over mutable state inside a Future inside an Actor but I'm still interested to know if in this particular case it is correct or not?
In general, java.util.concurrent.ConcurrentHashMap is made for concurrent use. As long as you don't try to transport the closure to another machine, and you think through the implications of it being used concurrently (e.g. if you read a value, use a function to modify it, and then put it back, do you want to use the replace(key, oldValue, newValue) method to make sure it hasn't changed while you were doing the processing?), it should be fine in Futures.
May be a little late, but still, in the book Reactive Web Applications, the author has indicated an indirection to this specific problem, using pipeTo as below.
def receive = {
case ComputeReach(tweetId) =>
fetchRetweets(tweetId, sender()) pipeTo self
case fetchedRetweets: FetchedRetweets =>
followerCountsByRetweet += fetchedRetweets -> List.empty
fetchedRetweets.retweets.foreach { rt =>
userFollowersCounter ! FetchFollowerCount(
fetchedRetweets.tweetId, rt.user
)
}
...
}
where followerCountsByRetweet is a mutable state of the actor. The result of fetchRetweets() which is a Future is piped to the same actor as a FetchedRetweets message, which then acts on the message on to modify the state of the acto., this will mitigate any concurrent operation on the state

spring integration message released twice from aggregator

I have a spring integration flow that starts with a channel inboundadapter and picks up files and passes them through the system as messages.
After a few components, the messages are aggregated at an "Aggregator" from where they are released based on release strategies or by group timeout of 30 sec.
The downstream processing has another bunch of components till the final one.
The problem I am facing is this,
When I send 33 files which create 33 "groups/buckets" based on correlation IDs, aggregated at the "Aggregator", some of the files or messages seems to be "released" twice. The reason I conclude that is because I have a channel interceptor which shows a few messages passing through the "released" channel (appearing right after the aggregator) a second time, after completing the downstream processing successfully, the first time. Additionally, this behavior causes my application to not find a file and throw an exception which I see. This leads me to conclude that the message bucket/group/corrID is somehow being "Released" twice.
I have tried to debug this many ways , but essentially, I want to know how a corrID/bucket after being released and having successfully gone through all downstream components in a single thread, can be "released" again.
My question is, how can I debug this? I want to know what is making this message/bucket re-appear in the aggregator.
My aggregator is as follows,
<int:aggregator id="bufferedFiles" input-channel="inQueueForStage"
output-channel="released" expire-groups-upon-completion="true"
send-partial-result-on-expiry="true" release-strategy="releaseHandler"
release-strategy-method="canRelease"
group-timeout-expression="size() > 0 ? T(com.att.datalake.ifr.loader.utils.MessageUtils).getAggregatorTimeout(one, #sourceSnapshot) : -1">
<int:poller fixed-delay="${files.pickup.delay:3000}"
max-messages-per-poll="${num.files.pickup.per.poll:10}"
task-executor="executor" />
</int:aggregator>
Explanation of aggregator: The size()>0 applies to EACH correlation bucket. each of the 33 files I am sending will spawn/generate/create a new bucket because of the file name, so the aggregator will have 33 buckets/groups/corrIds, each bucket will contain only one file.
So the aggregator SPEL expression simply says that if there no release strategies, then release the bucket/group after 30 secs if the group indeed has at least some files.
My Channel inbound adapter is as follows:
<int-file:inbound-channel-adapter id="files"
channel="dispatchFiles" directory="${source.dir}" scanner="directoryScanner">
<int:poller fixed-delay="${files.pickup.delay:3000}"
max-messages-per-poll="${num.files.pickup.per.poll:10}" />
</int-file:inbound-channel-adapter>
Logs
here is the log of message completing the flow the first time. The completion time invoked suggests reaching the last component a "completionHandler" SA.
Explanation of Log: "cor" is the bucket/corrId that is being released twice. The reason I get the final exception is because during the first time, the file is removed from that original location and processed. So the second time around when this erroneous release happens, there is nothing to process there.
From the pictures it can be seen that the first batch/corrId/bucket is processed and finished around 11:09, and the second one is started around 11:10
an important point I noticed that this behavior only happens when I have a global channel interceptor in which I am doing somewhat long processing. When this interceptor is commented out, the errors go away.
Question:
is it possible for aggregator to double release a batch/corrId under any circumstance? How can I make aggregator emit any logs?
Thanks
Edit 10:15pm
My channel following the aggregator has an interceptor as follows,
public Message<?> preSend(Message<?> message, MessageChannel channel) {
LOGGER.info("******** Releasing from aggregator(interceptor) , corrID:{} at time:{} ********",MessageUtils.getCorrelationId(message), new Date() );
finalReporter.callback(channel.toString(), message);
return message;
}
From Aggregator down to final compeltionHandler SA, I have single threaded processing
Aggregator -> releasedChannel -> some SA1 -> some channel -> ..... -> completionChannel->completeSA
When I run for 33 partitions, let's follow corrId = "alh" The first time it is released, it looks like following,
What it shows is that thread-5 released it and it should process all the downstream components. But it leaves it mid-way and starts doing other things and is picked up again by a diffferent thread a little later as follows,
That seems/seemed to be the problem,
Solution Update:
I did following 3 things to sort of work around, at the moment,
for some reason, my interceptors were doing return super.preSend(message, channel) instead of simply return message. I changed it to latter
I had a global channel interceptors, I removed global and kept individual ones
If the channel interceptors had any issues before returning, would that cause a new release?
Although I still see the above scenario depicted in pictures, I am not getting double processing attempts and as such it avoids the errors. I am still trying to make sense out of this.
I understand it's too specific and difficult to explain; still thanks for the time and comments...
However, yes. I think #GaryRussell is right: since you use expire-groups-upon-completion="true" some partial groups may be released by group-timeout-expression and the new messages with the same correlationId will form a new group, which is released by the next group-timeout. Your size() > 0 isn't good too. It means that it is going to release partial group after that group-timeout. Maybe size() > 1? The group can't be size() == 0 though. Because it is created on the first message, so, if gruop exists, it contains at least one message. Yes, group can be empty, but in that case the aggregator should be marked with expire-groups-upon-completion="false". In that case it is marked as completed and doesn't allow new messages.
After struggling with debugging and various blind scenarios, I believe that at least I have a workaround and a possible root cause. I will try to outline all the things that I modified,
Root Cause:
My interceptors were calling a Common class with a common callback method. This method, based on the channel name from which the request was coming from, would decide the appropriate action to take. The actions were essentially collecting data, incrementing counters and persisting to database some information.
It seems that some of them were having errors and consequently, the thread was dying and message re-released. I am not entirely sure about it and please correct me if that's not the case.
But after I fixed those errors, the re-release issue seems to have subsided or vanished altogether.
The reason it was hard to diagnose was because I could not see those errors thrown during callback method invocations; may be I was catching them or may be they were lost.
I also found that the issue was only on any channel interceptors AFTER the aggregator. Interceptors before the aggregator did not present any issues; may be because they were simpler...
To debug,
I removed the interceptors and made the callback directly from various components (SAs), removed global interceptors and tried to add individual interceptors for specific channels.
Thanks for all the help.

Relation between command handlers, aggregates, the repository and the event store in CQRS

I'd like to understand some details of the relations between command handlers, aggregates, the repository and the event store in CQRS-based systems.
What I've understood so far:
Command handlers receive commands from the bus. They are responsible for loading the appropriate aggregate from the repository and call the domain logic on the aggregate. Once finished, they remove the command from the bus.
An aggregate provides behavior and an internal state. State is never public. The only way to change state is by using the behavior. The methods that model this behavior create events from the command's properties, and apply these events to the aggregate, which in turn call an event handlers that sets the internal state accordingly.
The repository simply allows loading aggregates on a given ID, and adding new aggregates. Basically, the repository connects the domain to the event store.
The event store, last but not least, is responsible for storing events to a database (or whatever storage is used), and reloading these events as a so-called event stream.
So far, so good.
Now there are some issues that I did not yet get:
If a command handler is to call behavior on a yet existing aggregate, everything is quite easy. The command handler gets a reference to the repository, calls its loadById method and the aggregate is returned. But what does the command handler do when there is no aggregate yet, but one should be created? From my understanding the aggregate should later-on be rebuilt using the events. This means that creation of the aggregate is done in reply to a fooCreated event. But to be able to store any event (including the fooCreated one), I need an aggregate. So this looks to me like a chicken-and-egg problem: I can not create the aggregate without the event, but the only component that should create events is the aggregate. So basically it comes down to: How do I create new aggregates, who does what?
When an aggregate triggers an event, an internal event handler responses to it (typically by being called via an apply method) and changes the aggregate's state. How is this event handed over to the repository? Who originates the "please send the new events to the repository / event store" action? The aggregate itself? The repository by watching the aggregate? Someone else who is subscribed to the internal events? ...?
Last but not least I have a problem understanding the concept of an event stream correctly: In my imagination, it's simply something like an ordered list of events. What's of importance is that it's "ordered". Is this right?
The following is based on my own experience and my experiments with various frameworks like Lokad.CQRS, NCQRS, etc. I'm sure there are multiple ways to handle this. I'll post what makes most sense to me.
1. Aggregate Creation:
Every time a command handler needs an aggregate, it uses a repository. The repository retrieves the respective list of events from the event store and calls an overloaded constructor, injecting the events
var stream = eventStore.LoadStream(id)
var User = new User(stream)
If the aggregate didn't exist before, the stream will be empty and the newly created object will be in it's original state. You might want to make sure that in this state only a few commands are allowed to bring the aggregate to life, e.g. User.Create().
2. Storage of new Events
Command handling happens inside a Unit of Work. During command execution every resulting event will be added to a list inside the aggregate (User.Changes). Once execution is finished, the changes will be appended to the event store. In the example below this happens in the following line:
store.AppendToStream(cmd.UserId, stream.Version, user.Changes)
3. Order of Events
Just imagine what would happen, if two subsequent CustomerMoved events are replayed in the wrong order.
An Example
I'll try to illustrate the with a piece of pseudo-code (I deliberately left repository concerns inside the command handler to show what would happen behind the scenes):
Application Service:
UserCommandHandler
Handle(CreateUser cmd)
stream = store.LoadStream(cmd.UserId)
user = new User(stream.Events)
user.Create(cmd.UserName, ...)
store.AppendToStream(cmd.UserId, stream.Version, user.Changes)
Handle(BlockUser cmd)
stream = store.LoadStream(cmd.UserId)
user = new User(stream.Events)
user.Block(string reason)
store.AppendToStream(cmd.UserId, stream.Version, user.Changes)
Aggregate:
User
created = false
blocked = false
Changes = new List<Event>
ctor(eventStream)
isNewEvent = false
foreach (event in eventStream)
this.Apply(event, isNewEvent)
Create(userName, ...)
if (this.created) throw "User already exists"
isNewEvent = true
this.Apply(new UserCreated(...), isNewEvent)
Block(reason)
if (!this.created) throw "No such user"
if (this.blocked) throw "User is already blocked"
isNewEvent = true
this.Apply(new UserBlocked(...), isNewEvent)
Apply(userCreatedEvent, isNewEvent)
this.created = true
if (isNewEvent) this.Changes.Add(userCreatedEvent)
Apply(userBlockedEvent, isNewEvent)
this.blocked = true
if (isNewEvent) this.Changes.Add(userBlockedEvent)
Update:
As a side note: Yves' answer reminded me of an interesting article by Udi Dahan from a couple of years ago:
Don’t Create Aggregate Roots
A small variation on Dennis excellent answer:
When dealing with "creational" use cases (i.e. that should spin off new aggregates), try to find another aggregate or factory you can move that responsibility to. This does not conflict with having a ctor that takes events to hydrate (or any other mechanism to rehydrate for that matter). Sometimes the factory is just a static method (good for "context"/"intent" capturing), sometimes it's an instance method of another aggregate (good place for "data" inheritance), sometimes it's an explicit factory object (good place for "complex" creation logic).
I like to provide an explicit GetChanges() method on my aggregate that returns the internal list as an array. If my aggregate is to stay in memory beyond one execution, I also add an AcceptChanges() method to indicate the internal list should be cleared (typically called after things were flushed to the event store). You can use either a pull (GetChanges/Changes) or push (think .net event or IObservable) based model here. Much depends on the transactional semantics, tech, needs, etc ...
Your eventstream is a linked list. Each revision (event/changeset) pointing to the previous one (a.k.a. the parent). Your eventstream is a sequence of events/changes that happened to a specific aggregate. The order is only to be guaranteed within the aggregate boundary.
I almost agree with yves-reynhout and dennis-traub but I want to show you how I do this. I want to strip my aggregates of the responsibility to apply the events on themselves or to re-hydrate themselves; otherwise there is a lot of code duplication: every aggregate constructor will look the same:
UserAggregate:
ctor(eventStream)
foreach (event in eventStream)
this.Apply(event)
OrderAggregate:
ctor(eventStream)
foreach (event in eventStream)
this.Apply(event)
ProfileAggregate:
ctor(eventStream)
foreach (event in eventStream)
this.Apply(event)
Those responsibilities could be left to the command dispatcher. The command is handled directly by the aggregate.
Command dispatcher class
dispatchCommand(command) method:
newEvents = ConcurentProofFunctionCaller.executeFunctionUntilSucceeds(tryToDispatchCommand)
EventDispatcher.dispatchEvents(newEvents)
tryToDispatchCommand(command) method:
aggregateClass = CommandSubscriber.getAggregateClassForCommand(command)
aggregate = AggregateRepository.loadAggregate(aggregateClass, command.getAggregateId())
newEvents = CommandApplier.applyCommandOnAggregate(aggregate, command)
AggregateRepository.saveAggregate(command.getAggregateId(), aggregate, newEvents)
ConcurentProofFunctionCaller class
executeFunctionUntilSucceeds(pureFunction) method:
do this n times
try
call result=pureFunction()
return result
catch(ConcurentWriteException)
continue
throw TooManyRetries
AggregateRepository class
loadAggregate(aggregateClass, aggregateId) method:
aggregate = new aggregateClass
priorEvents = EventStore.loadEvents()
this.applyEventsOnAggregate(aggregate, priorEvents)
saveAggregate(aggregateId, aggregate, newEvents)
this.applyEventsOnAggregate(aggregate, newEvents)
EventStore.saveEventsForAggregate(aggregateId, newEvents, priorEvents.version)
SomeAggregate class
handleCommand1(command1) method:
return new SomeEvent or throw someException BUT don't change state!
applySomeEvent(SomeEvent) method:
changeStateSomehow() and not throw any exception and don't return anything!
Keep in mind that this is pseudo code projected from a PHP application; the real code should have things injected and other responsibilities refactored out in other classes. The ideea is to keep aggregates as clean as possible and avoid code duplication.
Some important aspects about aggregates:
command handlers should not change state; they yield events or
throw exceptions
event applies should not throw any exception and should not return anything; they only change internal state
An open-source PHP implementation of this could be found here.

Resources