@@ -9,9 +9,8 @@ a different bus (if the application has `multiple buses </messenger/multiple_bus
9
9
Any errors or exceptions that occur during this process can have unintended consequences,
10
10
such as:
11
11
12
- - If using the ``DoctrineTransactionMiddleware `` and a dispatched message to the same bus
13
- and an exception is thrown, then any database transactions in the original handler will
14
- be rolled back.
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.
15
14
- If the message is dispatched to a different bus, then the dispatched message can still
16
15
be handled even if the original handler encounters an exception.
17
16
@@ -32,29 +31,28 @@ will not be created because the ``DoctrineTransactionMiddleware`` will rollback
32
31
Doctrine transaction, in which the user has been created.
33
32
34
33
**Problem 2: ** If an exception is thrown when saving the user to the database, the welcome
35
- email is still sent.
34
+ email is still sent because it is handled asynchronously .
36
35
37
- ``HandleMessageInNewTransaction `` Middleware
38
- --------------------------------------------
36
+ ``DispatchAfterCurrentBusMiddleware `` Middleware
37
+ ------------------------------------------------
39
38
40
39
For many applications, the desired behavior is to have any messages dispatched by the handler
41
40
to `only ` be handled after the handler finishes. This can be by using the
42
- ``HandleMessageInNewTransaction `` middleware and adding a ``Transaction `` stamp to
43
- `the message Envelope </components/messenger#adding-metadata-to-messages-envelopes >`_.
44
- This middleware enables us to add messages to a separate transaction that will only be
45
- dispatched *after * the current message handler finishes.
41
+ ``DispatchAfterCurrentBusMiddleware `` middleware and adding a ``DispatchAfterCurrentBusStamp ``
42
+ stamp to `the message Envelope </components/messenger#adding-metadata-to-messages-envelopes >`_.
46
43
47
44
Referencing the above example, this means that the ``UserSignedUp `` event would not be handled
48
45
until *after * the ``SignUpUserHandler `` had completed and the new ``User `` was persisted to the
49
46
database. If the ``SignUpUserHandler `` encounters an exception, the ``UserSignedUp `` event will
50
47
never be handled and if an exception is thrown while sending the welcome email, the Doctrine
51
48
transaction will not be rolled back.
52
49
53
- To enable this, you need to add the ``handle_message_in_new_transaction ``
54
- middleware. Make sure it is registered before ``DoctrineTransactionMiddleware ``
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 ``
55
53
in the middleware chain.
56
54
57
- **Note: ** The ``handle_message_in_new_transaction `` middleware must be loaded for *all * of the
55
+ **Note: ** The ``dispatch_after_current_bus `` middleware must be loaded for *all * of the
58
56
buses. For the example, the middleware must be loaded for both the command and event buses.
59
57
60
58
.. configuration-block ::
@@ -70,13 +68,11 @@ buses. For the example, the middleware must be loaded for both the command and e
70
68
messenger.bus.command :
71
69
middleware :
72
70
- validation
73
- - handle_message_in_new_transaction
74
71
- doctrine_transaction
75
72
messenger.bus.event :
76
73
default_middleware : allow_no_handlers
77
74
middleware :
78
75
- validation
79
- - handle_message_in_new_transaction
80
76
- doctrine_transaction
81
77
82
78
@@ -89,7 +85,7 @@ buses. For the example, the middleware must be loaded for both the command and e
89
85
use App\Messenger\Event\UserSignedUp;
90
86
use Doctrine\ORM\EntityManagerInterface;
91
87
use Symfony\Component\Messenger\Envelope;
92
- use Symfony\Component\Messenger\Stamp\Transaction ;
88
+ use Symfony\Component\Messenger\Stamp\DispatchAfterCurrentBusStamp ;
93
89
use Symfony\Component\Messenger\MessageBusInterface;
94
90
95
91
class SignUpUserHandler
@@ -108,13 +104,44 @@ buses. For the example, the middleware must be loaded for both the command and e
108
104
$user = new User($command->getUuid(), $command->getName(), $command->getEmail());
109
105
$this->em->persist($user);
110
106
111
- // The Transaction stamp marks the event message to be handled
107
+ // The DispatchAfterCurrentBusStamp marks the event message to be handled
112
108
// only if this handler does not throw an exception.
113
109
114
110
$event = new UserSignedUp($command->getUuid());
115
111
$this->eventBus->dispatch(
116
112
(new Envelope($event))
117
- ->with(new Transaction ())
113
+ ->with(new DispatchAfterCurrentBusStamp ())
118
114
);
119
115
}
120
116
}
117
+
118
+ .. code-block :: php
119
+
120
+ namespace App\Messenger\EventSubscriber;
121
+
122
+ use App\Entity\User;
123
+ use App\Messenger\Event\UserSignedUp;
124
+ use Doctrine\ORM\EntityManagerInterface;
125
+
126
+ class WhenUserSignedUpThenSendWelcomeEmail
127
+ {
128
+ private $em;
129
+ private $mailer;
130
+
131
+ public function __construct(MyMailer $mailer, EntityManagerInterface $em)
132
+ {
133
+ $this->mailer = $mailer;
134
+ $this->em = $em;
135
+ }
136
+
137
+ public function __invoke(UserSignedUp $eent)
138
+ {
139
+ $user = $this->em->getRepository(User::class)->find(new User($event->getUuid()));
140
+
141
+ $this->mailer->sendWelcomeEmail($user);
142
+ }
143
+ }
144
+
145
+ **Note: ** If ``WhenUserSignedUpThenSendWelcomeEmail `` throws an exception, that exception
146
+ will be wrapped into a ``DelayedMessageHandlingException ``. Using ``DelayedMessageHandlingException::getExceptions ``
147
+ will give you all exceptions that are thrown while handing a message with the ``DispatchAfterCurrentBusStamp ``.
0 commit comments