10000 Symfony Messenger component documentation by sroze · Pull Request #9437 · symfony/symfony-docs · GitHub
[go: up one dir, main page]

Skip to content

Symfony Messenger component documentation #9437

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

Merged
merged 15 commits into from
Apr 16, 2018
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Fixed the RST syntax issues
  • Loading branch information
javiereguiluz authored Mar 18, 2018
commit b40bc7146c84647831d35f88e1d2cb6148af6240
149 changes: 99 additions & 50 deletions components/message.rst 10000
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,46 @@ The Message Component
The Message component helps application to send and receive messages
to/from other applications or via
Copy link
Member

Choose a reason for hiding this comment

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

This phrase looks unfinished. Also, it's not a very descriptive description. Should we mention at least "message bus" or some key concept so the readers know undoubtely what problem does this component solve? Thanks!


Installation
------------

.. code-block:: terminal

$ composer require symfony/message
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be symfony/messenger conform the composer.json.


Alternatively, you can clone the `<https://github.com/symfony/message>`_ repository.
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be https://github.com/symfony/messenger.


.. include:: /components/require_autoload.rst.inc

Concepts
--------

.. image:: /_images/components/message/overview.png
Copy link
Contributor
@andreybolonin andreybolonin Mar 26, 2018

Choose a reason for hiding this comment

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

image:: /_images/components/messenger/overview.png

Copy link
Contributor

Choose a reason for hiding this comment

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

messenger


1. **Sender**
Responsible for serializing and sending the message to _something_. This something can be a message broker or a 3rd
party API for example.
**Sender**:
Responsible for serializing and sending the message to _something_. This
something can be a message broker or a third party API for example.

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

3. **Handler**
Given a received message, contains the user business logic related to the message. In practice, that is just a PHP
callable.
**Handler**:
Given a received message, contains the user business logic related to the
message. In practice, that is just a PHP callable.

Bus
---

The bus is used to dispatch messages. MessageBus' behaviour is in its ordered middleware stack. When using
the message bus with Symfony's FrameworkBundle, the following middlewares are configured for you:
The bus is used to dispatch messages. MessageBus' behavior is in its ordered
middleware stack. When using the message bus with Symfony's FrameworkBundle, the
following middlewares are configured for you:

#. ``LoggingMiddleware`` (logs the processing of your messages)
#. ``SendMessageMiddleware`` (enables asynchronous processing)
#. ``HandleMessageMiddleware`` (calls the registered handle)

1. `LoggingMiddleware` (log the processing of your messages)
2. `SendMessageMiddleware` (enable asynchronous processing)
3. `HandleMessageMiddleware` (call the registered handle)
Example::

use App\Message\MyMessage;

Expand All @@ -42,9 +56,10 @@ the message bus with Symfony's FrameworkBundle, the following middlewares are co
Handlers
--------

Once dispatched to the bus, messages will be handled by a "message handler". A message handler is a PHP callable
(i.e. a function or an instance of a class) that will do the required processing for your message. It _might_ return a
result.
Once dispatched to the bus, messages will be handled by a "message handler". A
message handler is a PHP callable (i.e. a function or an instance of a class)
that will do the required processing for your message. It _might_ return a
result::

namespace App\MessageHandler;

Expand All @@ -58,43 +73,57 @@ result.
}
}

.. code-block:: xml
Copy link
Contributor

Choose a reason for hiding this comment

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

you should add yaml config format, too

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This has to be moved within the FrameworkBundle's documentation actually.


<service id="App\Handler\MyMessageHandler">
<tag name="message_handler" />
Copy link
Contributor

Choose a reason for hiding this comment

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

</service>

**Note:** If the message cannot be guessed from the handler's type-hint, use the `handles` attribute on the tag.
.. note::

### Asynchronous messages
If the message cannot be guessed from the handler's type-hint, use the
``handles`` attribute on the tag.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think best would be an example. Also mention that the guessing is done on the _invoke method argument


Using the Message Component is useful to decouple your application but it also very useful when you want to do some
asychronous processing. This means that your application will produce a message to a queuing system and consume this
Asynchronous messages
~~~~~~~~~~~~~~~~~~~~~

Using the Message Component is useful to decouple your application but it also
Copy link
Contributor
@andreybolonin andreybolonin Mar 26, 2018

Choose a reason for hiding this comment

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

Using the Messenger Component

Copy link
Contributor

Choose a reason for hiding this comment

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

Messenger

very useful when you want to do some asynchronous processing. This means that
your application will produce a message to a queuing system and consume this
message later in the background, using a _worker_.

#### Adapters
Adapters
~~~~~~~~

The communication with queuing system or 3rd parties is for delegated to libraries for now. You can use one of the
following adapters:
The communication with queuing system or third parties is for delegated to
libraries for now. You can use one of the following adapters:

- [PHP Enqueue bridge](https://github.com/sroze/enqueue-bridge) to use one of their 10+ compatible queues such as
RabbitMq, Amazon SQS or Google Pub/Sub.
#. `PHP Enqueue bridge`_ to use one of their 10+ compatible queues such as
RabbitMq, Amazon SQS or Google Pub/Sub.
Copy link
Contributor

Choose a reason for hiding this comment

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

RabbitMq -> RabbitMQ


Routing
-------

When doing asynchronous processing, the key is to route the message to the right sender. As the routing is
application-specific and not message-specific, the configuration can be made within the `framework.yaml`
configuration file as well:
When doing asynchronous processing, the key is to route the message to the right
sender. As the routing is application-specific and not message-specific, the
configuration can be made within the ``framework.yaml`` configuration file as
well:

.. code-block:: yaml

framework:
message:
Copy link
Contributor

Choose a reason for hiding this comment

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

messenger here and below

routing:
'My\Message\MessageAboutDoingOperationalWork': my_operations_queue_sender

Such configuration would only route the `MessageAboutDoingOperationalWork` message to be asynchronous, the rest of the
messages would still be directly handled.
Such configuration would only route the ``MessageAboutDoingOperationalWork``
message to be asynchronous, the rest of the messages would still be directly
handled.

If you want to do route all the messages to a queue by default, you can use such configuration:
If you want to do route all the messages to a queue by default, you can use such
configuration:

.. code-block:: yaml

framework:
message:
F438
Copy link
Contributor
@andreybolonin andreybolonin Mar 26, 2018

Choose a reason for hiding this comment

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

messenger:

Copy link
Contributor

Choose a reason for hiding this comment

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

messenger

Expand All @@ -104,6 +133,8 @@ If you want to do route all the messages to a queue by default, you can use such

Note that you can also route a message to multiple senders at the same time:

.. code-block:: yaml

framework:
message:
Copy link
Contributor
@andreybolonin andreybolonin Mar 26, 2018

Choose a reason for hiding this comment

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

messenger:

Copy link
Contributor

Choose a reason for hiding this comment

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

messenger

routing:
Expand All @@ -112,18 +143,20 @@ Note that you can also route a message to multiple senders at the same time:
Same bus received and sender
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To allow us to receive and send messages on the same bus and prevent a loop, the message bus is equipped with the
`WrapIntoReceivedMessage` received. It will wrap the received messages into `ReceivedMessage` objects and the
`SendMessageMiddleware` middleware will know it should not send these messages.
To allow us to receive and send messages on the same bus and prevent a loop, the
message bus is equipped with the ``WrapIntoReceivedMessage`` received. It will
Copy link
Contributor
@greg0ire greg0ire Mar 24, 2018

Choose a reason for hiding this comment

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

I'm having a hard time parsing this sentence, especially the last word 😕 . Either it should be a noun, or it should be "the received/obtained WrapIntoReceivedMessage object"

wrap the received messages into ``ReceivedMessage`` objects and the
``SendMessageMiddleware`` middleware will know it should not send these messages.

Your own sender
---------------

Using the `SenderInterface`, you can easily create your own message sender. Let's say you already have an
`ImportantAction` message going through the message bus and handled by a handler. Now, you also want to send this
message as an email.
Using the ``SenderInterface``, you can easily create your own message sender.
Let's say you already have an ``ImportantAction`` message going through the
message bus and handled by a handler. Now, you also want to send this message as
an email.

1. Create your sender
First, create your sender::

namespace App\MessageSender;

Expand Down Expand Up @@ -158,7 +191,9 @@ message as an email.
}
}

2. Register your sender service
Then, register your sender service:

.. code-block:: yaml

services:
App\MessageSender\ImportantActionToEmailSender:
Expand All @@ -169,27 +204,35 @@ message as an email.
tags:
- message.sender

3. Route your important message to the sender
Finally, route your important message to the sender:

.. code-block:: yaml

framework:
message:
routing:
'App\Message\ImportantAction': [App\MessageSender\ImportantActionToEmailSender, ~]

**Note:** this example shows you how you can at the same time send your message and directly handle it using a `null`
(`~`) sender.
.. note::

This example shows you how you can at the same time send your message and
directly handle it using a ``null`` (``~``) sender.

Your own receiver
-----------------

A consumer is responsible of receiving messages from a source and dispatching them to the application.
A consumer is responsible of receiving messages from a source and dispatching
them to the application.

Let's say you already proceed some "orders" on your application using a `NewOrder` message. Now you want to integrate with
a 3rd party or a legacy application but you can't use an API and need to use a shared CSV file with new orders.
Let's say you already proceed some "orders" on your application using a
Copy link
Contributor

Choose a reason for hiding this comment

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

processed != proceed

Copy link
Contributor

Choose a reason for hiding this comment

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

"in" your application?

``NewOrder`` message. Now you want to integrate with a 3rd party or a legacy
application but you can't use an API and need to use a shared CSV file with new
orders.

You will read this CSV file and dispatch a `NewOrder` message. All you need to do is your custom CSV consumer and Symfony will do the rest.
You will read this CSV file and dispatch a ``NewOrder`` message. All you need to
do is your custom CSV consumer and Symfony will do the rest.
Copy link
Contributor
@greg0ire greg0ire Mar 24, 2018

Choose a reason for hiding this comment

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

"to do" => "to do is create your…" or "to write is your…"

Copy link
Contributor

Choose a reason for hiding this comment

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

consumer -> receiver?


1. Create your receiver
First, create your receiver::

namespace App\MessageReceiver;

Expand Down Expand Up @@ -219,7 +262,9 @@ You will read this CSV file and dispatch a `NewOrder` message. All you need to d
}
}

2. Register your receiver service
Then, register your receiver service:

.. code-block:: yaml

services:
App\MessageReceiver\NewOrdersFromCsvFile:
Expand All @@ -230,6 +275,10 @@ You will read this CSV file and dispatch a `NewOrder` message. All you need to d
tags:
- message.receiver

3. Use your consumer
Finally, use your consumer:
Copy link
Contributor

Choose a reason for hiding this comment

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

consumer -> receiver?


.. code-block:: terminal

$ bin/console message:consume App\MessageReceived\NewOrdersFromCsvFile

Choose a reason for hiding this comment

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

Typo here, should be App\MessageReceiver\NewOrdersFromCsvFile


.. _`PHP Enqueue bridge`: https://github.com/sroze/enqueue-bridge
0