diff --git a/messenger/message-recorder.rst b/messenger/message-recorder.rst index 2a95e5b8bfc..4dd9c79e35e 100644 --- a/messenger/message-recorder.rst +++ b/messenger/message-recorder.rst @@ -1,7 +1,7 @@ .. index:: single: Messenger; Record messages; Transaction messages -Transactional Messages: Handle Events After CommandHandler is Done +Transactional Messages: Handle New Messages After Handling is Done ================================================================== A message handler can ``dispatch`` new messages during execution, to either the same or @@ -11,8 +11,8 @@ such as: - If using the ``DoctrineTransactionMiddleware`` and a dispatched message throws an exception, then any database transactions in the original handler will be rolled back. -- If the message is dispatched to a different bus, then dispatched message will be - handled even if the current handler throws an exception. +- If the message is dispatched to a different bus, then the dispatched message will + be handled even if some code later in the current handler throws an exception. An Example ``RegisterUser`` Process ----------------------------------- @@ -20,9 +20,9 @@ An Example ``RegisterUser`` Process Let's take the example of an application with both a *command* and an *event* bus. The application dispatches a command named ``RegisterUser`` to the command bus. The command is handled by the ``RegisterUserHandler`` which creates a ``User`` object, stores that object to a database and -dispatches a ``UserRegistered`` event to the event bus. +dispatches a ``UserRegistered`` message to the event bus. -There are many subscribers to the ``UserRegistered`` event, one subscriber may send +There are many handlers to the ``UserRegistered`` message, one handler may send a welcome email to the new user. We are using the ``DoctrineTransactionMiddleware`` to wrap all database queries in one database transaction. @@ -33,88 +33,14 @@ Doctrine transaction, in which the user has been created. **Problem 2:** If an exception is thrown when saving the user to the database, the welcome email is still sent because it is handled asynchronously. -``DispatchAfterCurrentBusMiddleware`` Middleware ------------------------------------------------- +DispatchAfterCurrentBusMiddleware Middleware +-------------------------------------------- -For many applications, the desired behavior is to have any messages dispatched by the handler -to `only` be handled after the handler finishes. This can be by using the +For many applications, the desired behavior is to *only* handle messages that are +dispatched by a handler once that handler has fully finished. This can be by using the ``DispatchAfterCurrentBusMiddleware`` middleware and adding a ``DispatchAfterCurrentBusStamp`` stamp to `the message Envelope `_. -Referencing the above example, this means that the ``UserRegistered`` event would not be handled -until *after* the ``RegisterUserHandler`` had completed and the new ``User`` was persisted to the -database. If the ``RegisterUserHandler`` encounters an exception, the ``UserRegistered`` event will -never be handled and if an exception is thrown while sending the welcome email, the Doctrine -transaction will not be rolled back. - -The ``dispatch_after_current_bus`` middleware is enabled by default. It is configured as the -first middleware on all busses. When doing a highly custom or special configuration, then make -sure ``dispatch_after_current_bus`` is registered before ``doctrine_transaction`` -in the middleware chain. - -**Note:** The ``dispatch_after_current_bus`` middleware must be loaded for *all* of the -buses. For the example, the middleware must be loaded for both the command and event bus. - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/messenger.yaml - framework: - messenger: - default_bus: messenger.bus.command - - buses: - messenger.bus.command: - middleware: - - validation - messenger.bus.event: - default_middleware: allow_no_handlers - middleware: - - validation - - .. code-block:: xml - - - - - - - - - - - - - - - - - - - - .. code-block:: php - - // config/packages/messenger.php - $container->loadFromExtension('framework', [ - 'messenger' => [ - 'default_bus' => 'messenger.bus.command', - 'buses' => [ - 'messenger.bus.command' => [ - 'middleware' => ['validation', 'doctrine_transaction'], - ], - 'messenger.bus.event' => [ - 'default_middleware' => 'allow_no_handlers', - 'middleware' => ['validation', 'doctrine_transaction'], - ], - ], - ], - ]); - .. code-block:: php namespace App\Messenger\CommandHandler; @@ -185,8 +111,20 @@ buses. For the example, the middleware must be loaded for both the command and e } } +This means that the ``UserRegistered`` message would not be handled +until *after* the ``RegisterUserHandler`` had completed and the new ``User`` was persisted to the +database. If the ``RegisterUserHandler`` encounters an exception, the ``UserRegistered`` event will +never be handled. And if an exception is thrown while sending the welcome email, the Doctrine +transaction will not be rolled back. + .. note:: If ``WhenUserRegisteredThenSendWelcomeEmail`` throws an exception, that exception will be wrapped into a ``DelayedMessageHandlingException``. Using ``DelayedMessageHandlingException::getExceptions`` will give you all exceptions that are thrown while handing a message with the ``DispatchAfterCurrentBusStamp``. + +The ``dispatch_after_current_bus`` middleware is enabled by default. If you're +configuring your middleware manually, be sure to register +``dispatch_after_current_bus`` before ``doctrine_transaction`` in the middleware +chain. Also, the ``dispatch_after_current_bus`` middleware must be loaded for *all* of +the buses being used.