Skip to content

Enhance messenger doc #10664

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 39 additions & 10 deletions components/messenger.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,33 @@ Concepts
something can be a message broker or a third party API for example.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be great if someone could edit the picture above in order to reflect Envelope usage inside the bus itself IMHO


**Receiver**:
Responsible for deserializing and forwarding messages to handler(s). This
can be a message queue puller or an API endpoint for example.
Responsible for retrieving, deserializing and forwarding messages to handler(s).
This can be a message queue puller or an API endpoint for example.

**Handler**:
Responsible for handling messages using the business logic applicable to the messages.
Handlers are called by the ``HandleMessageMiddleware`` middleware.

**Middleware**:
Middleware can access the message and its wrapper (the envelope) while it is
dispatched through the bus.
Literally *"the software in the middle"*, those are not about core concerns
(business logic) of an application. Instead, they are cross cutting concerns
applicable throughout the application and affecting the entire message bus.
For instance: logging, validating a message, starting a transaction, ...
They are also responsible for calling the next middleware in the chain,
which means they can tweak the envelope, by adding items to it or even
replacing it, as well as interrupt the middleware chain.

**Envelope**
Messenger specific concept, it gives full flexibility inside the message bus,
by wrapping the messages into it, allowing to add useful information inside
through *envelope items*.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for 4.2 merge:

- *envelope items*
+ *envelope stamps*


**Envelope Items**
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for 4.2 merge:

- **Envelope Items**
+ **Envelope Stamp**

Piece of information you need to attach to your message: serializer context
to use for transport, markers identifying a received message or any sort of
metadata your middleware or transport layer may use.

Bus
---
Expand All @@ -53,9 +75,9 @@ middleware stack. The component comes with a set of middleware that you can use.
When using the message bus with Symfony's FrameworkBundle, the following middleware
are configured for you:

#. ``LoggingMiddleware`` (logs the processing of your messages)
#. ``SendMessageMiddleware`` (enables asynchronous processing)
#. ``HandleMessageMiddleware`` (calls the registered handle)
#. :class:`Symfony\\Component\\Messenger\\Middleware\\LoggingMiddleware` (logs the processing of your messages)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for 4.2 merge: beware of the new FQCNs (already changed)

#. :class:`Symfony\\Component\\Messenger\\Asynchronous\\Middleware\\SendMessageMiddleware` (enables asynchronous processing)
#. :class:`Symfony\\Component\\Messenger\\Middleware\\HandleMessageMiddleware` (calls the registered handler(s))

Example::

Expand All @@ -74,7 +96,7 @@ Example::

.. note::

Every middleware needs to implement the ``MiddlewareInterface``.
Every middleware needs to implement the :class:`Symfony\\Component\\Messenger\\Middleware\\MiddlewareInterface`.

Handlers
--------
Expand Down Expand Up @@ -112,7 +134,7 @@ the ``SerializerConfiguration`` envelope::
]))
);

At the moment, the Symfony Messenger has the following built-in envelopes:
At the moment, the Symfony Messenger has the following built-in envelope items:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for 4.2 merge:

- envelope items
+ envelope stamps


#. :class:`Symfony\\Component\\Messenger\\Transport\\Serialization\\SerializerConfiguration`,
to configure the serialization groups used by the transport.
Expand Down Expand Up @@ -151,6 +173,12 @@ The above example will forward the message to the next middleware with an additi
envelope item *if* the message has just been received (i.e. has the `ReceivedMessage` item).
You can create your own items by implementing :class:`Symfony\\Component\\Messenger\\EnvelopeAwareInterface`.

.. note::

Any envelope item must be php serializable if going through transport using
Copy link
Contributor Author

@ogizanagi ogizanagi Nov 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for 4.2 merge:

- Any envelope item must be php serializable
+ Any stamp must be serializable using the Symfony Serializer component

Would solve #10276 I guess.

the :class:`Symfony\\Component\\Messenger\\Transport\\Serialization\\Serializer`
base serializer.

Transports
----------

Expand All @@ -160,7 +188,8 @@ transport will be responsible for communicating with your message broker or 3rd
Your own Sender
~~~~~~~~~~~~~~~

Using the ``SenderInterface``, you can create your own message sender.
Using the :class:`Symfony\\Component\\Messenger\\Transport\\SenderInterface`,
you can create your own message sender.
Imagine that you already have an ``ImportantAction`` message going through the
message bus and being handled by a handler. Now, you also want to send this
message as an email.
Expand Down Expand Up @@ -206,7 +235,7 @@ First, create your sender::
Your own Receiver
~~~~~~~~~~~~~~~~~

A receiver is responsible for receiving messages from a source and dispatching
A receiver is responsible for getting messages from a source and dispatching
them to the application.

Imagine you already processed some "orders" in your application using a
Expand All @@ -226,7 +255,7 @@ First, create your receiver::
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Messenger\Envelope;

class NewOrdersFromCsvFile implements ReceiverInterface
class NewOrdersFromCsvFileReceiver implements ReceiverInterface
{
private $serializer;
private $filePath;
Expand Down
92 changes: 47 additions & 45 deletions messenger.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ message handler. It's a class with an ``__invoke`` method::

Message handlers must be registered as services and :doc:`tagged </service_container/tags>`
with the ``messenger.message_handler`` tag. If you're using the
:ref:`default services.yaml configuration <service-container-services-load-example>`,
:ref:`default services.yaml configuration <service-container-services-load-example>` and implement
:class:`Symfony\\Component\\Messenger\\Handler\\MessageHandlerInterface`
or :class:`Symfony\\Component\\Messenger\\Handler\\MessageSubscriberInterface`,
this is already done for you, thanks to :ref:`autoconfiguration <services-autoconfigure>`.

If you're not using service autoconfiguration, then you need to add this config:
Expand Down Expand Up @@ -543,11 +545,16 @@ for each bus looks like this:
#. ``call_message_handler`` middleware. Will call the message handler(s) for the
given message.

Adding your own Middleware
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. note::

As described in the component documentation, you can add your own middleware
within the buses to add some extra capabilities like this:
These middleware names are actually shortcuts working by convention.
The real service ids are prefixed with the ``messenger.middleware.`` namespace.

Disabling default Middleware
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you don't want the default collection of middleware to be present on your bus,
you can disable them like this:

.. configuration-block::

Expand All @@ -558,9 +565,7 @@ within the buses to add some extra capabilities like this:
messenger:
buses:
messenger.bus.default:
middleware:
- 'App\Middleware\MyMiddleware'
- 'App\Middleware\AnotherMiddleware'
default_middleware: false

.. code-block:: xml

Expand All @@ -576,10 +581,7 @@ within the buses to add some extra capabilities like this:

<framework:config>
<framework:messenger>
<framework:bus name="messenger.bus.default">
<framework:middleware id="App\Middleware\MyMiddleware" />
<framework:middleware id="App\Middleware\AnotherMiddleware" />
</framework:bus>
<framework:bus name="messenger.bus.default" default-middleware="false" />
</framework:messenger>
</framework:config>
</container>
Expand All @@ -591,23 +593,17 @@ within the buses to add some extra capabilities like this:
'messenger' => array(
'buses' => array(
'messenger.bus.default' => array(
'middleware' => array(
'App\Middleware\MyMiddleware',
'App\Middleware\AnotherMiddleware',
),
'default_middleware' => false,
),
),
),
));

Note that if the service is abstract, a different instance of service will be
created per bus.

Disabling default Middleware
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Adding your own Middleware
~~~~~~~~~~~~~~~~~~~~~~~~~~

If you don't want the default collection of middleware to be present on your bus,
you can disable them like this:
As described in the component documentation, you can add your own middleware
within the buses to add some extra capabilities like this:

.. configuration-block::

Expand All @@ -618,7 +614,9 @@ you can disable them like this:
messenger:
buses:
messenger.bus.default:
default_middleware: false
middleware:
- 'App\Middleware\MyMiddleware'
- 'App\Middleware\AnotherMiddleware'

.. code-block:: xml

Expand All @@ -634,7 +632,10 @@ you can disable them like this:

<framework:config>
<framework:messenger>
<framework:bus name="messenger.bus.default" default-middleware="false" />
<framework:bus name="messenger.bus.default">
<framework:middleware id="App\Middleware\MyMiddleware" />
<framework:middleware id="App\Middleware\AnotherMiddleware" />
</framework:bus>
</framework:messenger>
</framework:config>
</container>
Expand All @@ -646,12 +647,18 @@ you can disable them like this:
'messenger' => array(
'buses' => array(
'messenger.bus.default' => array(
'default_middleware' => false,
'middleware' => array(
'App\Middleware\MyMiddleware',
'App\Middleware\AnotherMiddleware',
),
),
),
),
));

Note that if the service is abstract, a different instance of the service will
be created per bus.

Using Middleware Factories
~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand All @@ -674,13 +681,13 @@ factories. Defining such requires a two-step configuration based on Symfony's

# Step 2: an abstract definition that will call the factory with default
# arguments or the ones provided in the middleware config
messenger.middleware.doctrine_transaction_middleware:
messenger.middleware.doctrine_transaction:
class: Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddleware
factory: 'doctrine.orm.messenger.middleware_factory.transaction:createMiddleware'
abstract: true
# the default arguments to use when none provided from config. Example:
# middleware:
# - doctrine_transaction_middleware: ~
# - doctrine_transaction: ~
arguments: ['default']

.. code-block:: xml
Expand All @@ -703,7 +710,7 @@ factories. Defining such requires a two-step configuration based on Symfony's

<!-- Step 2: an abstract definition that will call the factory with default
arguments or the ones provided in the middleware config -->
<service id="messenger.middleware.doctrine_transaction_middleware"
<service id="messenger.middleware.doctrine_transaction"
class="Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddleware"
abstract="true">

Expand All @@ -729,7 +736,7 @@ factories. Defining such requires a two-step configuration based on Symfony's

// Step 2: an abstract definition that will call the factory with default
// arguments or the ones provided in the middleware config
$container->register('messenger.middleware.doctrine_transaction_middleware', DoctrineTransactionMiddleware::class)
$container->register('messenger.middleware.doctrine_transaction', DoctrineTransactionMiddleware::class)
->setFactory(array(
new Reference('doctrine.orm.messenger.middleware_factory.transaction'),
'createMiddleware'
Expand All @@ -742,7 +749,7 @@ which is the argument expected by the
``Symfony\Bridge\Doctrine\Messenger\DoctrineTransactionMiddlewareFactory::createMiddleware`` method.

Then you can reference and configure the
``messenger.middleware.doctrine_transaction_middleware`` service as a middleware:
``messenger.middleware.doctrine_transaction`` service as a middleware:

.. configuration-block::

Expand All @@ -755,9 +762,9 @@ Then you can reference and configure the
command_bus:
middleware:
# Using defaults
- doctrine_transaction_middleware
- doctrine_transaction
# Using another entity manager
- doctrine_transaction_middleware: ['custom']
- doctrine_transaction: ['custom']

.. code-block:: xml

Expand All @@ -775,9 +782,9 @@ Then you can reference and configure the
<framework:messenger>
<framework:bus name="command_bus">
<!-- Using defaults -->
<framework:middleware id="doctrine_transaction_middleware" />
<framework:middleware id="doctrine_transaction" />
<!-- Using another entity manager -->
<framework:middleware id="doctrine_transaction_middleware">
<framework:middleware id="doctrine_transaction">
<framework:argument>custom</framework:argument>
</framework:middleware>
</framework:bus>
Expand All @@ -794,20 +801,15 @@ Then you can reference and configure the
'command_bus' => array(
'middleware' => array(
// Using defaults
'doctrine_transaction_middleware',
'doctrine_transaction',
// Using another entity manager
array('id' => 'doctrine_transaction_middleware', 'arguments' => array('custom')),
array('id' => 'doctrine_transaction', 'arguments' => array('custom')),
),
),
),
),
));

.. note::

The ``doctrine_transaction_middleware`` shortcut is a convention. The real
service id is prefixed with the ``messenger.middleware.`` namespace.

.. note::

Middleware factories only allow scalar and array arguments in config (no
Expand All @@ -816,9 +818,9 @@ Then you can reference and configure the

.. tip::

The ``doctrine_transaction_middleware`` is a built-in middleware wired
automatically when the DoctrineBundle and the Messenger component are
installed and enabled.
The ``messenger.middleware.doctrine_transaction`` middleware is a built-in
middleware wired automatically when the DoctrineBundle and the Messenger
component are installed and enabled.

Your own Transport
------------------
Expand Down