[Messenger] Added documentation about DispatchAfterCurrentBusMiddleware#10015
[Messenger] Added documentation about DispatchAfterCurrentBusMiddleware#10015Nyholm wants to merge 13 commits intosymfony:masterfrom
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.
- 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``. |
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.
- 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.
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.
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.
- 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.
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.
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.
We're missing use statements for domain classes, what about:
use App\Entity\User;
use App\Messenger\Command\CreateUser;
use App\Messenger\Event\UserCreatedEvent;?
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.
- 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``. |
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.
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.
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.
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.
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.
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.
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 |
arnolanglade
left a comment
There was a problem hiding this comment.
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.
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.
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.
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.
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.
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.
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 |
sroze
left a comment
There was a problem hiding this comment.
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