Skip to content

Commit 5c71a61

Browse files
committed
Merge branch '4.3'
* 4.3: minor reorg of new DispatchAfterCurrentBusMiddleware
2 parents 145d60d + bfccca2 commit 5c71a61

File tree

1 file changed

+49
-106
lines changed

1 file changed

+49
-106
lines changed

messenger/message-recorder.rst

Lines changed: 49 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,49 @@
11
.. index::
22
single: Messenger; Record messages; Transaction messages
33

4-
Transactional Messages: Handle Events After CommandHandler is Done
4+
Transactional Messages: Handle New Messages After Handling is Done
55
==================================================================
66

7-
A message handler can ``dispatch`` new messages during execution, to either the same or
8-
a different bus (if the application has `multiple buses </messenger/multiple_buses>`_).
9-
Any errors or exceptions that occur during this process can have unintended consequences,
10-
such as:
7+
A message handler can ``dispatch`` new messages during execution, to either the
8+
same or a different bus (if the application has
9+
`multiple buses </messenger/multiple_buses>`_). Any errors or exceptions that
10+
occur during this process can have unintended consequences, such as:
1111

12-
- If using the ``DoctrineTransactionMiddleware`` and a dispatched message throws an exception,
13-
then any database transactions in the original handler will be rolled back.
14-
- If the message is dispatched to a different bus, then dispatched message will be
15-
handled even if the current handler throws an exception.
12+
- If using the ``DoctrineTransactionMiddleware`` and a dispatched message throws
13+
an exception, then any database transactions in the original handler will be
14+
rolled back.
15+
- If the message is dispatched to a different bus, then the dispatched message
16+
will be handled even if some code later in the current handler throws an
17+
exception.
1618

1719
An Example ``RegisterUser`` Process
1820
-----------------------------------
1921

20-
Let's take the example of an application with both a *command* and an *event* bus. The application
21-
dispatches a command named ``RegisterUser`` to the command bus. The command is handled by the
22-
``RegisterUserHandler`` which creates a ``User`` object, stores that object to a database and
23-
dispatches a ``UserRegistered`` event to the event bus.
22+
Let's take the example of an application with both a *command* and an *event*
23+
bus. The application dispatches a command named ``RegisterUser`` to the command
24+
bus. The command is handled by the ``RegisterUserHandler`` which creates a
25+
``User`` object, stores that object to a database and dispatches a
26+
``UserRegistered`` message to the event bus.
2427

25-
There are many subscribers to the ``UserRegistered`` event, one subscriber may send
28+
There are many handlers to the ``UserRegistered`` message, one handler may send
2629
a welcome email to the new user. We are using the ``DoctrineTransactionMiddleware``
2730
to wrap all database queries in one database transaction.
2831

29-
**Problem 1:** If an exception is thrown when sending the welcome email, then the user
30-
will not be created because the ``DoctrineTransactionMiddleware`` will rollback the
31-
Doctrine transaction, in which the user has been created.
32-
33-
**Problem 2:** If an exception is thrown when saving the user to the database, the welcome
34-
email is still sent because it is handled asynchronously.
35-
36-
``DispatchAfterCurrentBusMiddleware`` Middleware
37-
------------------------------------------------
38-
39-
For many applications, the desired behavior is to have any messages dispatched by the handler
40-
to `only` be handled after the handler finishes. This can be by using the
41-
``DispatchAfterCurrentBusMiddleware`` middleware and adding a ``DispatchAfterCurrentBusStamp``
42-
stamp to `the message Envelope </components/messenger#adding-metadata-to-messages-envelopes>`_.
43-
44-
Referencing the above example, this means that the ``UserRegistered`` event would not be handled
45-
until *after* the ``RegisterUserHandler`` had completed and the new ``User`` was persisted to the
46-
database. If the ``RegisterUserHandler`` encounters an exception, the ``UserRegistered`` event will
47-
never be handled and if an exception is thrown while sending the welcome email, the Doctrine
48-
transaction will not be rolled back.
49-
50-
The ``dispatch_after_current_bus`` middleware is enabled by default. It is configured as the
51-
first middleware on all busses. When doing a highly custom or special configuration, then make
52-
sure ``dispatch_after_current_bus`` is registered before ``doctrine_transaction``
53-
in the middleware chain.
54-
55-
**Note:** The ``dispatch_after_current_bus`` middleware must be loaded for *all* of the
56-
buses. For the example, the middleware must be loaded for both the command and event bus.
57-
58-
.. configuration-block::
59-
60-
.. code-block:: yaml
61-
62-
# config/packages/messenger.yaml
63-
framework:
64-
messenger:
65-
default_bus: messenger.bus.command
66-
67-
buses:
68-
messenger.bus.command:
69-
middleware:
70-
- validation
71-
messenger.bus.event:
72-
default_middleware: allow_no_handlers
73-
middleware:
74-
- validation
75-
76-
.. code-block:: xml
77-
78-
<!-- config/packages/messenger.xml -->
79-
<?xml version="1.0" encoding="UTF-8" ?>
80-
<container xmlns="http://symfony.com/schema/dic/services"
81-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
82-
xmlns:framework="http://symfony.com/schema/dic/symfony"
83-
xsi:schemaLocation="http://symfony.com/schema/dic/services
84-
https://symfony.com/schema/dic/services/services-1.0.xsd">
85-
86-
<framework:config>
87-
<framework:messenger default_bus="messenger.bus.command">
88-
<framework:bus name="messenger.bus.command">
89-
<framework:middleware id="validation">
90-
<framework:middleware id="doctrine_transaction">
91-
</framework:bus>
92-
<framework:bus name="messenger.bus.command" default_middleware="allow_no_handlers">
93-
<framework:middleware id="validation">
94-
<framework:middleware id="doctrine_transaction">
95-
</framework:bus>
96-
</framework:messenger>
97-
</framework:config>
98-
</container>
99-
100-
.. code-block:: php
101-
102-
// config/packages/messenger.php
103-
$container->loadFromExtension('framework', [
104-
'messenger' => [
105-
'default_bus' => 'messenger.bus.command',
106-
'buses' => [
107-
'messenger.bus.command' => [
108-
'middleware' => ['validation', 'doctrine_transaction'],
109-
],
110-
'messenger.bus.event' => [
111-
'default_middleware' => 'allow_no_handlers',
112-
'middleware' => ['validation', 'doctrine_transaction'],
113-
],
114-
],
115-
],
116-
]);
32+
**Problem 1:** If an exception is thrown when sending the welcome email, then
33+
the user will not be created because the ``DoctrineTransactionMiddleware`` will
34+
rollback the Doctrine transaction, in which the user has been created.
11735

118-
.. code-block:: php
36+
**Problem 2:** If an exception is thrown when saving the user to the database,
37+
the welcome email is still sent because it is handled asynchronously.
38+
39+
DispatchAfterCurrentBusMiddleware Middleware
40+
--------------------------------------------
41+
42+
For many applications, the desired behavior is to *only* handle messages that
43+
are dispatched by a handler once that handler has fully finished. This can be by
44+
using the ``DispatchAfterCurrentBusMiddleware`` and adding a
45+
``DispatchAfterCurrentBusStamp`` stamp to
46+
`the message Envelope </components/messenger#adding-metadata-to-messages-envelopes>`_::
11947

12048
namespace App\Messenger\CommandHandler;
12149

@@ -185,8 +113,23 @@ buses. For the example, the middleware must be loaded for both the command and e
185113
}
186114
}
187115
116+
This means that the ``UserRegistered`` message would not be handled until
117+
*after* the ``RegisterUserHandler`` had completed and the new ``User`` was
118+
persisted to the database. If the ``RegisterUserHandler`` encounters an
119+
exception, the ``UserRegistered`` event will never be handled. And if an
120+
exception is thrown while sending the welcome email, the Doctrine transaction
121+
will not be rolled back.
122+
188123
.. note::
189124

190-
If ``WhenUserRegisteredThenSendWelcomeEmail`` throws an exception, that exception
191-
will be wrapped into a ``DelayedMessageHandlingException``. Using ``DelayedMessageHandlingException::getExceptions``
192-
will give you all exceptions that are thrown while handing a message with the ``DispatchAfterCurrentBusStamp``.
125+
If ``WhenUserRegisteredThenSendWelcomeEmail`` throws an exception, that
126+
exception will be wrapped into a ``DelayedMessageHandlingException``. Using
127+
``DelayedMessageHandlingException::getExceptions`` will give you all
128+
exceptions that are thrown while handing a message with the
129+
``DispatchAfterCurrentBusStamp``.
130+
131+
The ``dispatch_after_current_bus`` middleware is enabled by default. If you're
132+
configuring your middleware manually, be sure to register
133+
``dispatch_after_current_bus`` before ``doctrine_transaction`` in the middleware
134+
chain. Also, the ``dispatch_after_current_bus`` middleware must be loaded for
135+
*all* of the buses being used.

0 commit comments

Comments
 (0)