It was quite a ride so far. We have seen commands, command buses, events and event buses. We distilled some more knowledge about them while formulating answers to some interesting questions from readers.
Why you should not dispatch events while handling a command
In a previous post we discussed a sample event (the UserSignedUp
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;
}
}
An instance of such an event can be handed over to the event bus. It will look for any number of event handlers that
wants to be notified about the event. In the case of the UserSignedUp
event, one of the interested event handlers is
the SendWelcomeMailWhenUserSignedUp
handler:
class SendWelcomeMailWhenUserSignedUp implements EventHandler
{
...
public function handle(Event $event)
{
$user = $this->userRepository->getById($event->userId());
$this->userMailer->sendWelcomeMailTo($user);
}
}
The UserSignedUp
event occurs whenever a SignUpUser
command has been handled. We might be tempted to inject the
event bus into the command handler and let it handle the event immediately:
class SignUpHandler
{
public function __construct(EventBus $eventBus, ...)
{
$this->eventBus = $eventBus;
...
}
public function handle($command)
{
...
$this->userRepository->add($user);
$event = new UserSignedUp($user->id());
$this->eventBus->handle($event);
}
}
We should not forget however that this command is handled within a database transaction created by one of the command buses. And as I already mentioned, we don't want the event to be handled within the same transaction, since it could endanger the success of that transaction. Also, when the transaction fails in the end, we might end up handling an event for entities whose actual state is insecure.
So instead, we should merely collect events while handling the command and only hand them over to the event bus when the transaction was committed, i.e. when we know that the command has been successfully and completely handled.
Event providers
Of course, SimpleBus
would not be complete without an out-of-the-box implementation of this kind of delayed event
handling. The connecting concept between events and the command bus is the ProvidesEvents
interface, which is part of
the SimpleBus/EventBus package.
namespace SimpleBus\Event\Provider;
use SimpleBus\Event\Event;
interface ProvidesEvents
{
/**
* @return Event[]
*/
public function releaseEvents();
}
You can provide a simple implementation for such an EventProvider
by defining a class for it, which uses the trait
EventProviderCapabilities
. This adds the ability to collect events (using the raise()
method) and release them
later, using the releaseEvents()
method:
use SimpleBus\Event\Provider\EventProviderCapabilities;
class EventProvider implements ProvidesEvents
{
use EventProviderCapabilities;
}
We could inject this EventProvider
into any command handler and use the raise()
method of the EventProvider
to
raise new events (which will not be handled right-away, but only stored in-memory):
class SignUpHandler
{
public function __construct(EventProvider $eventProvider, ...)
{
$this->eventProvider = $eventProvider;
...
}
public function handle($command)
{
...
$event = new UserSignedUp($user->id());
$this->eventProvider->raise($event);
}
}
Now, at what point could we safely release the events collected by the EventProvider
and hand those events over to the
event bus? The answer is: in yet another command bus! We simply wrap the new event-aware command bus which starts and
commits the database transaction. Only then can we be sure that the transaction was successful and we can proceed to
safely dispatch the collected events.
Since SimpleBus/CommandBus
and SimpleBus/EventBus
are stand-alone packages, I introduced a bridge package between
the two, SimpleBus/CommandEventBridge. It contains this class, which
is a CommandBus
, but asks the event provider to release its events, and lets the EventBus
instance handle them:
class DispatchesEvents implements CommandBus
{
use RemembersNext;
private $eventProvider;
private $eventBus;
public function __construct(ProvidesEvents $eventProvider, EventBus $eventBus)
{
$this->eventBus = $eventBus;
$this->eventProvider = $eventProvider;
}
public function handle(Command $command)
{
$this->next($command);
foreach ($this->eventProvider->releaseEvents() as $event) {
$this->eventBus->handle($event);
}
}
}
In a diagram this would look something like this (from left to right it shows you the passage of time):
Conclusion
After reading this series about command and event buses, you can start using commands to interact with your application and events to act upon the things that happened. Because both the command and the event bus are highly extensible you have many options for introducing more advanced behavior. You could think of:
- Collecting events in an store
- Handling commands asynchronously
- The same for events
- ...
For now we are more or less done talking about command and event buses. If you have questions, just write a comment below this post. I'm currently working on version 2.0 of the SimpleBus packages. You can at least expect a new post when I'm done, to announce the changes with respect to 1.0. To give you a sneak peek:
- Code for command and event buses will be generalized and bundled in the MessageBus package.
- Instead of wrapping message buses using composition, this new package introduces the concept of message bus middlewares, offering greater flexibility and cleaner code for your own specialized message bus features.
Hey Matthias,
What about raising events in the Entity rather than in the Command?
How would you go about it using the EventProvider?
I am thinking, maybe we raise the events in the entity and store them in an array. In the Command Handler we can then use the EventProvider to collect the events from the Entity.
What do you think?
Thanks
Certainly, that's how I do it these days: an entity collecs the events, you take them out and dispatch them. SimpleBus does this by the way, if you use the DoctrineBridge. But you can easily do it without a bus.
Hi, I've seen code where they add events to an array within an entity and are dispatched later on. Where is this talked about ? any chance you could get the URL of that post ? thank you very much !
Actually, I've read about it in this actual post :)) I've read so many stuff lately that i forgot where I got the knowledge from.
Cheers!
Thanks for the quick reply!
I am using Tactician for my command bus implementation, should be easy to switch to SimpleBus. I use a transaction middleware that also takes care of flushing and I want to add one more in the chain to take care of the event dispatching. I think I've read about that in another one of your posts, really helpful!
Thanks a lot!
Nice :) Well, I'm sure you can replicate this behavior with Tactician as well, and if I remember correctly, there's a similar Doctrine-plugin for Tactician too.
Hello, is there any special reason why the SimpleBus/CommandEventBridge package is now deprecated?
Hi, the reason why is that the CommandBus and EventBus merged in one package (message-bus) (because both using the same base class, MessageBusSupportingMiddleware). Here a example of a custom bus with support of events and asynchronous handling with bernard: https://gist.github.com/Axx...
Hi Matthias. I have seen you use these three class names for event suscribers:
SendWelcomeMailWhenUserSignedUp
UserRegisteredEventSubscriber
UserRegisteredEventsHandler
I think the first is better but probably we would have a a lot of EventHandlers. One for each secondary task (http://php-and-symfony.matt...)
Thanks for pointing this out. Yes, each specialized event subscriber should have a name describing what it does in particular. There may be events with no subscribers, and some events may have many subscribers.
Great series Matthias, thanks a lot for writing them, very interesting! One question I have related to db transactions: you say they shouldn't be nested. For example, you mention in a previous article "The first command wasn't fully handled yet. In fact, the database transaction hasn't even been closed yet, so now both commands are being handled within the same transaction. Which is totally undesirable since the second command may fail,
and take the first command down in its fall."
But what if the business need is the other way around? What if one failed transaction should make sure all transactions are rolled back? Just think of any financial/bank application: one Command might do a transfer from account A to B, another Command from B to C, yet another Command from C to D, etc. If any one of them would fail, all of them should be rolled back.
If, as in your example, you let one transaction complete (transfer money from A to B) but then the second transaction fails (B to C), you end up with incorrect amounts of money in the accounts.
Could you wrap both transfers in the same command?
Great work Matthias. I am trying to implement a Symfony sample with all this stuff but I have a problem: I do not know how to make the DispatchesEvents CommandBus works. Event handlers are not being called.
More details: https://github.com/josecela...
Hi Jose, I'm still finalizing the libraries - next up: looking at your demo application and adding it to the list of sample projects in the documentation. By the way, some other people are making demo applications too!
Is there an default implementation of EventProvider class inside SimpleBus?
Yes, in version 2.0 it's
RecordsMessages
(https://github.com/SimpleBu...RecordsMessages is an interface not a class. I was wondering if there is a default implementation service (Symsony) which you could inject inside a command handler to dispatch events after the command is done.
Ah, sorry about that. I'm thinking about adding one, yes. And now that you ask for it, I will. It is going to be a simple class which implements that interface and uses the
MessageRecorderCapabilities
trait (https://github.com/SimpleBu....Cool! Tnx!
There you go: https://github.com/SimpleBu... Documented here: http://simplebus.github.io/... And I will add a message_recorder service to the Symfony bridge as well.
Wow thats fast! But why did you not use the MessageRecorderCapabilities trait?
Ah! Well, I was trying to, but it already has the protected record() method. I didn't want to make it public, since I think that it should not always be possible to record messages from the outside. So I chose to repeat just this little bit of code. Another option would have been to split the trait of course, but for now it's fine I think.
This is great stuff Matthias. Once this series is complete and SimpleBus stable I would love to see a working example app. I am understanding the concepts but am having trouble picturing them all working together in a real world application.
Thanks! And I got that request several times :) I will create something to demonstrate everything in a single app.
You already have an example Matthias? Thanks for this series
Sorry, no!
When should we use Command Bus and when to use Application Service?
I assume these two are the approaches in Application layer of Domain Driven Design?
Correct me if I am wrong.
Cheers,
Xu
Hi Xu, command handlers may call application services, or they can even replace them.
Thanks for clarification. Matthias