From commands to events

Posted on by Matthias Noback

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 Commands, the CommandBus and CommandHandlers: 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.

If you're interested to learn more about these subjects and start using commands and events in your (Symfony) application, check out my Hexagonal Architecture training website.
PHP hexagonal architecture command bus events event bus SimpleBus
Comments
This website uses MailComments: you can send your comments to this post by email. Read more about MailComments, including suggestions for writing your comments (in HTML or Markdown).
AdriĆ 

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

Matthias Noback

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).

Cydrick Nonog

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

Matthias Noback

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).

Cydrick Nonog

Hi @matthiasnoback:disqus ,

Thank you for your great answer.

Michael

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?

Matthias Noback

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.

Jeroen Desloovere

Why do you do $event = new UserSignedUp($user->id()); and not $event = new UserSignedUp($user);?

webDEVILopers

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?

webDEVILopers

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.

Javier Seixas

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.

webDEVILopers

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?

Laurent Demouge

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);
}
}

jerry

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

Adam Sebastian

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" ?

Giorgio Sironi

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.

Matthias Noback

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!

Cliff

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?

Matthias Noback

I discussed this in the most recent post - if you have questions about this, please let me know!

Jacob Kiers

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?

Matthias Noback

That's correct - I seem to have already changed it :)

Tommi

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 ?

Conall O'Reilly

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.

Matthias Noback

Well put, Conall!

Luciano Mammino

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!

Matthias Noback

Thanks! 2.0 will be available soon :)

tim glabisch

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

tim glabisch

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.

Matthias Noback

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.

tim glabisch

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? :)

Steven Musumeche

Why does Symfony's event dispatcher require a name? Does it offer some advantage that your package doesn't?

Matthias Noback

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.

Steven Musumeche

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.