-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[Messenger] Added documentation about DispatchAfterCurrentBusMiddleware #10015
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@Nyholm thanks for this contribution! Lately in the Symfony Docs we're trying to not add new articles when they are too short. So, do you think we could move this article to a section inside an existing article? If there is no article where we can put this ... or if such article is already super long, we could consider creating this new article. Thanks! |
messenger/message-recorder.rst
Outdated
|
||
.. code-block:: yaml | ||
|
||
# config/packages/workflow.yaml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- workflow.yaml
+ messenger.yaml
messenger/message-recorder.rst
Outdated
Record Events Produced by a Handler | ||
=================================== | ||
|
||
In a example application there is a command (a CQRS message) named ``CreateUser``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"In an example"
messenger/message-recorder.rst
Outdated
=================================== | ||
|
||
In a example application there is a command (a CQRS message) named ``CreateUser``. | ||
That command is handled by the ``CreateUserHandler``. The command handler creates |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- by the ``CreateUserHandler``. The command handler creates
+ by the ``CreateUserHandler`` which creates
?
messenger/message-recorder.rst
Outdated
|
||
In a example application there is a command (a CQRS message) named ``CreateUser``. | ||
That command is handled by the ``CreateUserHandler``. The command handler creates | ||
a ``User`` object, stores that object to a database and dispatches an ``UserCreatedEvent``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"a UserCreatedEvent"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost :) I'm not native. But you wrote "a User" just before. See https://english.stackexchange.com/questions/105116/is-it-a-user-or-an-user
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say that "a User" was a typo.
I read your source. I did not know that. Thank you. I've updated the PR.
messenger/message-recorder.rst
Outdated
There are many subscribers to the ``UserCreatedEvent``, one subscriber may send | ||
a welcome email to the new user. Since we are using the ``DoctrineTransactionMiddleware`` | ||
we wrap all database queries in one database transaction and rollback that transaction | ||
if an exception is thrown. That would mean that if an exception is thrown when sending |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- That would mean
+ That means
messenger/message-recorder.rst
Outdated
- messenger.middleware.validation | ||
- messenger.middleware.handles_recorded_messages: ['@messenger.bus.event'] | ||
# Doctrine transaction must be after handles_recorded_messages middleware | ||
- app.doctrine_transaction_middleware: ['default'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about using an FQCN for app.doctrine_transaction_middleware
? or may we explicit the definition somewhere. If possible I'd rather use the class name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have an idea that this will be on the same page as #10013 where we use app.doctrine_transaction_middleware
.
messenger/message-recorder.rst
Outdated
$this->em = $em; | ||
} | ||
|
||
public function __invoke(CreateUser $command) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're missing use statements for domain classes, what about:
use App\Entity\User;
use App\Messenger\Command\CreateUser;
use App\Messenger\Event\UserCreatedEvent;
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you
messenger/message-recorder.rst
Outdated
Record Events Produced by a Handler | ||
=================================== | ||
|
||
In an example application there is a command (a CQRS message) named ``CreateUser``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- In an example application there is a command (a CQRS message) named ``CreateUser``.
+ Let's take the example of an application that has a command (a CQRS message) named ``CreateUser``.
?
messenger/message-recorder.rst
Outdated
|
||
In an example application there is a command (a CQRS message) named ``CreateUser``. | ||
That command is handled by the ``CreateUserHandler`` which creates | ||
a ``User`` object, stores that object to a database and dispatches a ``UserCreatedEvent``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UserCreated
event?
messenger/message-recorder.rst
Outdated
That event is also a normal message but is handled by an *event* bus. | ||
|
||
There are many subscribers to the ``UserCreatedEvent``, one subscriber may send | ||
a welcome email to the new user. Since we are using the ``DoctrineTransactionMiddleware`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest to split the two and explicit the "problem":
- Since we are using the ``DoctrineTransactionMiddleware`` [...]
+ We are using the ``DoctrineTransactionMiddleware`` to wrap all database queries in one database transaction.
+
+ **Problem:** if an exception is thrown when sending the welcome email, then the user will not be created because the ``DoctrineTransactionMiddleware`` will rollback the Doctrine transaction, in which the user has been created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. Thank you
messenger/message-recorder.rst
Outdated
if an exception is thrown. That means that if an exception is thrown when sending | ||
the welcome email, then the user will not be created. | ||
|
||
The solution to this issue is to not dispatch the ``UserCreatedEvent`` in the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, I'd highlight the solution:
**Solution:**
messenger/message-recorder.rst
Outdated
.. index:: | ||
single: Messenger; Record messages | ||
|
||
Record Events Produced by a Handler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be better to find a name that describes the problem than the technical solution. Something like "Event recorder: Tolerating failures while in Doctrine transactions"?
messenger/message-recorder.rst
Outdated
$user = new User($command->getUuid(), $command->getName(), $command->getEmail()); | ||
$this->em->persist($user); | ||
|
||
$this->eventRecorder->record(new UserCreatedEvent($command->getUuid()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to explain what this does, right? Because it does more than "recording" the event. Actually, this call does postpone the event dispatching isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The EventRecorder is just a storage. There is a middleware that reads from that store later. But yes, I'll write something
Thank you for the review. I've updated the PR accordingly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to add a rich model User
with a named constructor signUp
that will recored a SignedUpUser
event.
messenger/message-recorder.rst
Outdated
Events Recorder: Handle Events After CommandHandler Is Done | ||
=========================================================== | ||
|
||
Let's take the example of an application that has a command (a CQRS message) named |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a CQRS message
but message. You suer messages too when you application use the CQS pattern for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, CQRS doesn't necessitate any form of messages. Could "an imperative domain message" be an option? Or maybe a more thorough definition could be useful.
messenger/message-recorder.rst
Outdated
=========================================================== | ||
|
||
Let's take the example of an application that has a command (a CQRS message) named | ||
``CreateUser``. That command is handled by the ``CreateUserHandler`` which creates |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be better to use SignUpUser
as command name, it is less focus on CRUD action.
messenger/message-recorder.rst
Outdated
$this->em->persist($user); | ||
|
||
// "Record" this event to be processed later by "handles_recorded_messages". | ||
$this->eventRecorder->record(new UserCreatedEvent($command->getUuid()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This event should be produced by the user model.
messenger/message-recorder.rst
Outdated
Events Recorder: Handle Events After CommandHandler Is Done | ||
=========================================================== | ||
|
||
Let's take the example of an application that has a command (a CQRS message) named |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, CQRS doesn't necessitate any form of messages. Could "an imperative domain message" be an option? Or maybe a more thorough definition could be useful.
messenger/message-recorder.rst
Outdated
``CreateUserHandler`` but to just "record" the events. The recorded events will | ||
be dispatched after ``DoctrineTransactionMiddleware`` has committed the transaction. | ||
|
||
To enable this, you simply just add the ``messenger.middleware.handles_recorded_messages`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should remove "simply just", because it's just filler, and not everyone would consider this simple.
The current PR symfony/symfony#28849 replaces the RecordsMessages middleware and recorder with a My rewrite is here: https://github.com/gubler/messenger-transaction-test/blob/master/docs/transactional-messages.rst I tried to take into account previous comments on this request. Feel free to take whatever is useful from my rewrite. |
Done - though its the first time I've done this, so I apologize if I messed anything up :/ |
We should not forget this: symfony/symfony#28849 (comment) |
I did some updates to the docs to keep up-to-date with the symfony PR. I also added some screenshots to this PR description. I hope they will address any questions about the functionality and to help you (everyone) to help me explain this in the docs. |
…t bus is finished (Nyholm) This PR was merged into the 4.3-dev branch. Discussion ---------- [Messenger] Support for handling messages after current bus is finished | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | | License | MIT | Doc PR | symfony/symfony-docs#10015 This is a replacement for #27844. We achieve the same goals without introducing the new concept of "recorder". ```php class CreateUserHandler { private $em; private $eventBus; public function __construct(MessageBus $eventBus, EntityManagerInterface $em) { $this->eventBus = $eventBus; $this->em = $em; } public function __invoke(CreateUser $command) { $user = new User($command->getUuid(), $command->getName(), $command->getEmail()); $this->em->persist($user); $message = new UserCreatedEvent($command->getUuid(); $this->eventBus->dispatch((new Envelope($message))->with(new DispatchAfterCurrentBus())); } } ``` Note that this `DispatchAfterCurrentBusMiddleware` is added automatically as the first middleware. 2019-03-13: I updated the PR description. Commits ------- 903355f Support for handling messages after current bus is finished
Thank you @Nyholm! |
@sroze could you add your review? |
The current PR is for HandleMessageInNewTransaction middleware instead of the original RecordsMessages middleware. This documentation covers the new middleware.
Co-Authored-By: Nyholm <tobias.nyholm@gmail.com>
Co-Authored-By: Nyholm <tobias.nyholm@gmail.com>
Co-Authored-By: Nyholm <tobias.nyholm@gmail.com>
Co-Authored-By: Nyholm <tobias.nyholm@gmail.com>
.. index:: | ||
single: Messenger; Record messages; Transaction messages | ||
|
||
Transactional Messages: Handle Events After CommandHandler is Done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@javiereguiluz s/After/after/ ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except these few details, it looks good to me 👍
Thank you for the review. I've updated accordingly |
Thank you for merging. |
…dleware entry (weaverryan) This PR was merged into the 4.3 branch. Discussion ---------- [Messenger] Tweaks for DispatchAfterCurrentBusMiddleware entry Just some proofreading changes for symfony#10015! Commits ------- 599d10b minor reorg of new DispatchAfterCurrentBusMiddleware
Documentation to PR: symfony/symfony#27844