In the previous posts we looked at commands and the command bus. Commands are simple objects which express a user's intention to change something. Internally, the command object is handed over to the command bus, which performs the change that has been requested. While it eventually delegates this task to a dedicated command handler, it also takes care of several other things, like wrapping the command execution in a database transaction and protecting the original order of commands.
Secondary tasks
When a command has been handled by its corresponding command handler, there may be other things that need to be done.
For example, when the SignUp
command from the previous examples was successfully handled by the SignUpHandler
, it
may be useful to afterwards:
- Send a welcome message to the new user by email,
- Set up a personal profile page for the new user,
- Increase the "current number of users" statistic, which will be displayed on the administrator's dashboard,
- And so on...
We may be tempted to perform all of these actions inside the SignUpHandler
:
class SignUpHandler
{
public function __construct(
UserRepository $userRepository,
UserMailer $userMailer,
ProfileService $profileService,
UserStatistics $userStatistics
) {
$this->userRepository = $userRepository;
$this->userMailer = $userMailer;
$this->profileService = $profileService;
$this->userStatistics = $userStatistics;
}
public function handle($command)
{
$user = User::signUp(
$command->emailAddress,
$command->password
);
$this->userRepository->add($user);
$this->userMailer->sendWelcomeMailTo($user);
$this->profileService->setUpProfilePageForUser($user);
$this->userStatistics->increment('number_of_users');
}
}
Why the command handler should not perform secondary tasks
There are several major disadvantages to this approach.
First, we need to be aware that the code of this handler is executed within a single database transaction. When
something fails along the way (sending the email, talking to the Redis server that contains the number_of_users
statistic, etc.), the entire operation fails. The user is not signed up after all, because the transaction is being
rolled back. If we are very unlucky, a welcome mail has been sent to the user, after which incrementing the statistic
fails. This would cause the transaction to be rolled back and the data of the signed up user will never actually be
persisted, meaning that the user experience becomes quite inconsistent.
Second, we need to be clear about what it means to sign a user up. Of course, the welcome mail is important, and so is
the profile page and the statistic (although that one is merely a "nice to have"). Still, signing up a user is mainly
making sure that the user (which is represented in our application as a User
object) will be around longer than the
current request or session; the User
object should be persistent, i.e. added to the "repository" of users. Everything
else that happens while handling the SignUpUser
command should be considered secondary, or after the fact.
Third, the SignUpHandler
has responsibilities which cut across several application layers. Its main concern is
persisting the signed up user. All the secondary tasks currently performed by the SignUpHandler
are mostly related to
infrastructural concerns (e.g. sending emails, talking to a statistics server, etc.). This indicates a problem with
responsibilities: the SignUpHandler
violates the Single responsibility principle (SRP).
Fourth, even though the code in the SignUpHandler
still looks quite simple, I've left out all the details. You
probably need much more code to perform all the tasks well. This would quickly result in an unmaintainable, inflexible
class. Since you have to actually modify the code in SignUpHandler
to change any of its secondary behaviors, the class
appears to be closed for extension, meaning that the Open/closed principle (OCP) has not been honoured.
Introducing events
An excellent way to solve issues with SRP and OCP and to separate primary tasks from secondary tasks is to introduce events. Events, like many other things, are objects. And like commands, they only contain some data and display no behavior at all. They are messages.
Event objects can be created while handling a command. They should be published after the command has been fully handled. Event subscribers are then able to hook into the event system and perform their specific task when a particular type of event has taken place:
class SignUpHandler
{
...
public function handle($command)
{
$user = User::signUp($command->emailAddress, $command->password);
$this->userRepository->add($user);
// create the event
$event = new UserSignedUp($user->id());
// dispatch the event
$this->eventDispatcher->dispatch($event);
}
}
Looking for the best event dispatcher
You are probably already familiar with some kind of event system. Maybe you've used the Symfony event dispatcher, the Laravel event dispatcher, or the EventEmitter package from the League of Extraordinary Packages. Most of these event dispatchers/managers/emitters are not suitable for the task at hand. Let's first characterize our perfect event dispatcher for the situation described above:
- We want to pass an event object to the event dispatcher
- Every interested subscriber should be notified of the event
- Event subscribers should not be able to prevent other subscribers from being notified
- There should be no talking back to whoever dispatched the event
- It should be possible to store event messages and/or send them to some kind of a queue, for asynchronous processing
- The type of an event object corresponds to one particular event - we don't want to separately provide the event name
That's a nice list of requirements which is unfortunately not met by all of the event dispatchers I know:
- Some use arrays for the event data
- Most of them allow event subscribers to stop further propagation of the event
- Most of them offer event subscribers a way to talk back
- Most of them have options for prioritizing event handlers
- Most of them require two arguments when dispatching the event: an event name, and an event object
Introducing SimpleBus/EventBus
All of these features are undesirable or simply unnecessary in our use case. So for the dispatching of events from
within command handlers (or from any part of the application really), I created the
SimpleBus/EventBus package. It offers its own classes and interfaces for event
handling. Please note that you are always free to use the event dispatcher that you like best. Nothing in the the
CommandBus
package forces you to use the EventBus
package as well. The other way around applies here too: there's
nothing in the EventBus
package that forces you to use the CommandBus
package as well. They are complete decoupled.
The SimpleBus/EventBus
package contains what looks pretty much like an event dispatcher. However, to make it blend in
with the other SimpleBus
packages, I decided to mirror the terminology of Command
s, the CommandBus
and
CommandHandler
s: the EventBus
package has the interfaces Event
, EventBus
and EventHandler
.
An EventBus
, just like the CommandBus
, is just an anonymous bus to which you hand over an Event
object. And just
like CommandBus
, usually an EventBus
instance is wrapped by another EventBus
by composition. Another similarity is
that the EventBus
handles one event completely before handling the next event.
However, there are some major differences:
- While commands have exactly one corresponding command handler, there is a one-to-many correspondence between an event and its handlers. There may even be zero handlers for a particular event.
- Events are not (supposed to be) handled in a separate database transaction, like commands are.
Instead of "dispatching" an event, we let the EventBus
handle an Event
:
class UserSignedUp implements Event
{
public function name()
{
return 'user_signed_up';
}
public function __construct($userId)
{
$this->userId = $userId;
}
public function userId()
{
return $this->userId;
}
}
// $eventBus is an instance of EventBus
$eventBus = ...;
$userId = ...;
$event = new UserSignedUp($userId);
$eventBus->handle($event);
The secondary task of sending the welcome mail would be executed by one of the event handlers, like this:
class SendWelcomeMailWhenUserSignedUp implements EventHandler
{
public function __construct(
UserRepository $userRepository,
UserMailer $userMailer
) {
$this->userRepository = $userRepository;
$this->userMailer = $userMailer;
}
public function handle(Event $event)
{
$user = $this->userRepository->getById($event->userId());
$this->userMailer->sendWelcomeMailTo($user);
}
}
Conclusion
In this post we have seen the merits of using events and event handlers to move secondary tasks from command handlers.
We discussed the usage of the EventBus
and why and how it is provided as part of the SimpleBus/EventBus
package.
In most cases you would not directly call the event bus yourself. This should usually be done by the command bus after a command was successfully handled. In another post we will look at how the command bus can be made aware of the event bus and how we can collect events during the handling of a command.
Hello,
I am testing and I have many subscribers to one asynchronous event and they are executed sequentially, so if one fails, the next it won't be processed.
Is there a way, using a middleware or anything else to avoid this behaviour?
I do not understand why a subscriber will not be executed if the previous fails.
As I can see doing tests, all the subscribers are being executed in the same "transaction/thread".
Thanks
Sure, you could create your own middleware for it. By default there's
no transaction for event subscribers by the way. Instead of just
dispatching all recorded events, you can dispatch them one by one, catch
the optional exception, log it, and continue with the next event (or
event subscriber).
Hi,
I just want to know should I create a new Application Event instead of using the Domain Event,
Let say I have,
Domain Event UserWasCreated, this event will be save to Event Store
I want to to create a RegisteredEvent as Application Event, where this event will have handler like sending messages. And if ever where should I call to dispatch this event, in command handler or its better to create a service like, RegistrationService and this service will call command bus to handle the command and call the handler of RegisteredEvent
Thanks
Too many questions :) A command handler _is_ an application service, so if you have a command "SendRegistrationEmail", then just send it directly to the bus. If you do this in an event subscriber, you could listen to the event, then send a new command to the bus. Dispatching events can be done inside the application service, but if your command bus has middleware for dispatching events, you should wait until the command was fully handled (and optionally the database transaction was committed).
Hi @matthiasnoback:disqus ,
Thank you for your great answer.
Hi, everyone, just noticed:
Quote: "The type of an event object corresponds to one particular event - we don't want to separately provide the event name"
class UserSignedUp implements Event
{
public function name()
{
return 'user_signed_up';
}
By the way, Matthias recommend using instanceof instead of $event->name() doesn't he?
Hi Michael, thanks for pointing out the inconsistency here. Both options have their advantage. I used to be a proponent of having a name() method, with a hard-coded name, since it makes it possible to rename or move the entire class, and don't break the setup of the event listeners. But if your framework can catch up with that, there's no problem at all.
Why do you do
$event = new UserSignedUp($user->id());
and not$event = new UserSignedUp($user);
?It is recommended to only pass primitive types instead of objects that
may consume memory. But imagine an event-driven system with two bounded
contexts / microservices / isolated applications. Both may have a User
Entity - and maybe they also share the same database - but they both
look totally different because they designed for that special context.
The $user object from context1 would not look like $user from the
context2. Only pass what is really required for the event to be handled.
Your reply doesn't make perfect sense to me.
Firstly if the command is persisting a user, then that object should already exist in memory. Objects are passed by reference and therefore it's not going to consume much memory at all. In fact it'll probably consume less memory than the primitives you are copying.
Secondly, if you have multiple bounded contexts that's fine but it doesn't stop you from using a namespaced reference from a different bounded context surely? I appreciate that would mean coupling domain logic across bounded contexts but if you are consuming events from a different bounded context then surely you are already coupling?
Maybe my answer was too general. Regardind the original question:
It is better to pass a value object (or primitives) e.g. $user->id() instead of a full object $user.
Yea I understand this a bit better since asking the question. There's no reason to assume that an event will be consumed by the same application that triggers it. It could be sent of to a message queue so primitives are certainly the best option in that case.
I also read a post which mentioned that any changes to a VO would then potentially break your event handlers so it's better to just pass primitives.
Thanks for the great explanation! Although, there is something you mentioned here and I think another post on the subject would be quite useful, and that is sending the events to a queue and handling them later. Are you maybe planning a blog post on that? It could be quite helpful.
My main concerns are: how do I send an event to a queue server? (Use a standard event handler, perhaps? But would that be the right way?); also, some of the handlers could be unaware of the whole app, perhaps those could even be non-PHP. So, I would need to make sure my events are correctly serialised.
Hi Matthias,
I'm following very closely your samples about this topic, and a doubt came out: Do you test your handlers? If the answer is yes, how?
In my case, I'm using phpspec, and the way I'm doing is using an spy for checking that
userRepository->add($user) is called. I instantiate a user object twice. One in the handle method, and the second one in the test.
The problem comes when I generate a uuid during the user object instance. Since this uuid is different in each instance, my test fails.
Maybe you can bring some light to my problem. Thanks in advance.
Where would I place my form framework when using a handler? Just before creating the Command e.g. in a Controller. Then - if the form is validated - I pass the valid data to the Command?
ATM I have my validation constraints set on the Model / Entity. Should I add a FormHandler instead that has its own validation rules?
Hi Matthias, thx for all this very valuable blog series !
Just a simple question :
does it sound like a correct method to inject the whole Bus in commandHandlers so the latter could call $this->messageBus->dispatch($events);
Class OneCommandHandler
{
private $messageBus;
//.....
public function handle(Command $command)
{
//..... will at some points hopefully returns DomainEvents
}
private function dispatch(DomainEvents $events)
{
$this->messageBus->dispatch($events);
}
}
A debt of gratitude is in order for this awesome post, i think that it exceptionally intriguing and extremely well thoroughly considered and set up together. I anticipate perusing your work later on.
Web Design Agency
This is a nice approach, but I do find using events dispatchers to make code a bit harder to understand. What are the drawbacks of using a service (e.g. SignUpService) to handle this by requiring the command and then doing the work of a commandbus/eventbus by explicitly calling the "event subscribers" ?
Are you aware of CQRS and its Command/Aggregate/DomainEvent patterns? It seems there is a host of good knowledge there that overlaps with this post.
Hi Giorgio, yes, I am aware of those. This series of posts is meant to introduce the underlying ideas without them being embedded in a particular "movement" - however, I agree that this context might/should be added. I will, in a later post. Thanks!
Are the events handled by the EventBus being executed during or after the command is being executed. You talked about the commands being inside a transaction and any code executed during that and fails could rollback the command. But if the events are being dispatched during the command this could still happen right?
I discussed this in the most recent post - if you have questions about this, please let me know!
I believe the section "Why the event handler should not perform secondary tasks" should be "Why the command handler should not perform secondary tasks". Is that correct?
That's correct - I seem to have already changed it :)
Hi could you explain why features like "
Allowing event subscribers to stop further propagation of the event" and "prioritizing events handlers" are not welcome for event handlers for commands/handlers ?
I can't speak for matthias, but I think you expose your system to a lot of unknown/risky behaviour when you make your event life cycle too flexible. Conceptually, it's good to view an event as something that happened in the past that cannot be changed - an immutable fact represented by a value object. It is for each individual listener/handler to decide on whether or not they should take any action based on the event. For example, maybe you only have two event handlers, SendWelcomeEmail, and SendWelcomeTextMessage, but you only want to send an email if the new user didn't provide a phone number on registration.
You could organise it so that the event is always dispatched to SendWelcomeTextMessage before SendWelcomeEmail, and then, if the user has a phone number and the text was sent, invoke $event->stopPropogation() to prevent SendWelcomeEmail from ever being reached. That's quite complicated, and not very scalable (you may have many more event handlers for the same event in the future). Simpler, is to not care about the order in which they are invoked, and simply put the logic for whether or not to send an email, in the SendWelcomeEmail handler itself.
Well put, Conall!
Great article as usual Matthias. I really like this approach based on command and event buses.
I really look forward to adopt your new libraries!
Thanks! 2.0 will be available soon :)
thanks for this post.
i don't get why you need a command bus to execute the commands.
why not just injecting the Handler and execute the command? where is the benefit to intorduce the command bus indirection?
Probably to make presentation layer as dumb as possible
can't get the reason, @matthiasnoback:disqus, can you give me a hint? if there is a one to one relation between commandhandlers, i dont see any benefit to use an event bus. using a handler + interface and injection the handler looks cleaner to me.
The command/event bus supports middlewares, which allows you to silently execute all kinds of behavior before or after handling the command/event. Like wrapping the handling in a transaction, logging things, sending them off to some message queue, etc. Directly calling the handler would be possible, but you'd miss all these great auto-functionality.
wrapping could be solved using a decorator, changing using dependency injection. transactions sounds really weird because you need to know what you wrap, so this is very coupled and the coupling is hidden. silently is more an anti pattern? :)
Why does Symfony's event dispatcher require a name? Does it offer some advantage that your package doesn't?
The Symfony event dispatcher allows the same type of event objects to be used for different events, or put differently: the name of an event is not controlled by the event (object) itself. In my library it's the other way around.
I see. I use Symfony in my projects and the name part is always annoying because I only ever use one name with one type of event, so it feels like duplication.