-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[Messenger] Add the Envelope in the documentation #9757
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made some minor tweaks (please check to make sure I didn't change anything important - was just meant to be language tweaks. And, 2 questions
components/messenger.rst
Outdated
{ | ||
public function handle($message, callable $next) | ||
{ | ||
// $message here is an `Envelope` object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it always an Envelope? Or maybe it could be an Envolope?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's always an Envelope
if you implements the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: that's true considering our bus implementation which will always inject the message wrapped in an Envelope. But we currently also use Envelope::wrap
in envelope aware middleware and most tests are calling handle
on envelope aware middleware with a message directly, not an envelope.
We could remove Envelope::wrap
and fix tests of these middleware, but IMHO it's still another hint symfony/symfony#27322 is needed for clarity & better design.
components/messenger.rst
Outdated
|
||
return $next( | ||
$message->with(new AnotherEnvelopeItem(/* ... */)) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the main use-case for an envelop-aware middleware? Or would we more commonly be reading some configuration from the envelope?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both are good use cases tbh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think reading would be way more common and should be showcased instead. I would put a note about being extra cautious about altering the envelope or its message as it'll be completely transparent. Even if there are legit use-cases.
About altering/replacing the message, the tactician docs says:
You don’t have to pass the same command to $next that came in! If you’re working with a legacy system and want to convert or modify the incoming commands, you’re free to do so. Just think carefully!
Also showing an example where we read the envelope items would make the purpose of those items more understandable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I as about to (try to) work on this. Thanks for taking care of it ❤️
Should we update the schema in order to represent that receivers get a message wrapped into an envelope and senders send an Envelope too?
Adding an Envelope
entry below it would be helpful too (with a link to this new section).
components/messenger.rst
Outdated
])) | ||
); | ||
|
||
Instead of dealing directly with the message in the handlers or middleware, you |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handlers will always get the message (and I think it should stay as is as the end of the pipe), never the Envelope, so I think mentioning handlers here is misleading.
components/messenger.rst
Outdated
|
||
return $next( | ||
$message->with(new AnotherEnvelopeItem(/* ... */)) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think reading would be way more common and should be showcased instead. I would put a note about being extra cautious about altering the envelope or its message as it'll be completely transparent. Even if there are legit use-cases.
About altering/replacing the message, the tactician docs says:
You don’t have to pass the same command to $next that came in! If you’re working with a legacy system and want to convert or modify the incoming commands, you’re free to do so. Just think carefully!
Also showing an example where we read the envelope items would make the purpose of those items more understandable.
components/messenger.rst
Outdated
It will wrap the received messages into ``ReceivedMessage`` objects and the | ||
``SendMessageMiddleware`` middleware will know it should not route these | ||
messages again to a transport. | ||
It will add a ``ReceivedMessage`` configuration to the message envelopes and the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- configuration
+ marker item
?
components/messenger.rst
Outdated
@@ -188,6 +235,6 @@ Receiver and Sender on the same bus | |||
|
|||
To allow us to receive and send messages on the same bus and prevent an infinite | |||
loop, the message bus is equipped with the ``WrapIntoReceivedMessage`` middleware. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, the WrapIntoReceivedMessage
is neither a middleware, neither it is used in Symfony core. That's the Worker
that call the receive
method with a $handler
adding the ReceivedMessage
marker to the envelope.
Hence I wondered multiple times if it was really intended? Should we remove the WrapIntoReceivedMessage
decorator? Should we decorate in the core any created receiver? Should the worker only dispatch the received envelope to the bus, or keep adding ReceivedMessage
?
'groups' => ['my_serialization_groups'], | ||
])) | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could mention others built-in configurations available (just ValidationConfiguration
for now) here or in another section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just did 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated :)
'groups' => ['my_serialization_groups'], | ||
])) | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just did 👍
@weaverryan can you have another look please? |
components/messenger.rst
Outdated
{ | ||
// $message here is an `Envelope` object, because this middleware | ||
// implements the EnvelopeAwareInterface interface. Otherwise, | ||
// it would be the "original" message. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should remove the last sentence. I think it's obvious that, if you do NOT implement ``EnvelopeAwareInterface`, that you receive the normal message. So, this sentence made me wonder if you were actually saying something different.
components/messenger.rst
Outdated
// implements the EnvelopeAwareInterface interface. Otherwise, | ||
// it would be the "original" message. | ||
|
||
if (null !== $message->get(ReceivedMessage::class)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this get()
method something that lives on Envelope
? Isn't there always just one message inside an Envelope? If so, why do we pass an argument here? Or, could you also pass something like $message->get(SerializerConfiguration::class)
to get those types of things out?
Also, suppose some similar code: if $message->get(MyMessage::class)
is null, does it mean that this message is NOT originally a MyMessage
isntance, right? I mean, it's equivalent to !$message instanceof MyMessage
in a middleware without EnvelopAwareInterface
?
Some inline comments with some of these answers might be all we need :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, is it a real use-case to look need to know whether or not a message was just received? If you're using an async transport and you want to do something for a specific message type, is it important that you make sure this processing is done only when your message has been "received"? If so, why? And if so, how could I both perform my action only when the message is "received" AND only check the class of the original message (e.g. I need to do something when my MyMessage
class is "received"? Or is that totally not the correct pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if $message->get(MyMessage::class) is null, does it mean that this message is NOT originally a MyMessage isntance, right?
There is mis interpretation here. The ReceivedMessage
class is not an example here, it's an actual envelope item within the component has is a marker that represents that the message has just been received. It's needed to have the router middleware ignoring them (otherwise we would have a receive -> send) loop.
Or, could you also pass something like $message->get(SerializerConfiguration::class) to get those types of things out?
That's not also, that's the only thing you can do :)
how could I both perform my action only when the message is "received" AND only check the class of the original message
if (nul !== $message->get(ReceivedMessage::class) && $message->getMessage() instanceof YourOwnMessageClass) {
// Your logic...
}
Might be clearer if we rename $message
to $envelope
?
components/messenger.rst
Outdated
@@ -86,6 +86,65 @@ that will do the required processing for your message:: | |||
} | |||
} | |||
|
|||
Envelope |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The title of this section and the introduction is not very clear to me. Here is a reword proposal:
Before:
Envelope
--------
The notion of an envelope is a concept that helps add context around the
messages. An envelope is a message and a set of data. From a user's perspective, this
allows you to set some configuration around the message. For example, to set the serialization
groups used when the message goes through the transport layer, wrap your message
in an ``Envelope`` and add some ``SerializerConfiguration``::
After:
Adding Metadata to Messages (Envelopes)
---------------------------------------
If you need to add metadata or some configuration to a message, wrap it with the
:class:`Symfony\\Component\\Messenger\\Envelope` class. For example, to set the
serialization groups used when the message goes through the transport layer, use
the ``SerializerConfiguration`` envelope::
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much better 👍
Ping to @sroze. Will you have some time to fix the final issues of this PR? Thanks! |
components/messenger.rst
Outdated
@@ -86,6 +86,65 @@ that will do the required processing for your message:: | |||
} | |||
} | |||
|
|||
Envelope |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much better 👍
components/messenger.rst
Outdated
|
||
class MyOwnMiddleware implements MiddlewareInterface, EnvelopeAwareInterface | ||
{ | ||
public function handle($message, callable $next) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, maybe we can rename $message
to $envelope
in this example? PHP allows us to do so (i.e. variable names not to match with the name in the interface). It might be clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Please rename this.
components/messenger.rst
Outdated
// implements the EnvelopeAwareInterface interface. Otherwise, | ||
// it would be the "original" message. | ||
|
||
if (null !== $message->get(ReceivedMessage::class)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if $message->get(MyMessage::class) is null, does it mean that this message is NOT originally a MyMessage isntance, right?
There is mis interpretation here. The ReceivedMessage
class is not an example here, it's an actual envelope item within the component has is a marker that represents that the message has just been received. It's needed to have the router middleware ignoring them (otherwise we would have a receive -> send) loop.
Or, could you also pass something like $message->get(SerializerConfiguration::class) to get those types of things out?
That's not also, that's the only thing you can do :)
how could I both perform my action only when the message is "received" AND only check the class of the original message
if (nul !== $message->get(ReceivedMessage::class) && $message->getMessage() instanceof YourOwnMessageClass) {
// Your logic...
}
Might be clearer if we rename $message
to $envelope
?
2ed4789
to
dd8b368
Compare
@javiereguiluz pong :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good. Just that minor change renaming the variable
Thank you @sroze! Sorry for the delay! I did rename the variable to $envelope as suggested. Cheers! |
…e, weaverryan) This PR was merged into the 4.1 branch. Discussion ---------- [Messenger] Add the Envelope in the documentation Because we've merged this beautiful PR :) Commits ------- a87d727 Renaming variable 16c7385 Merge branch '4.1' into messenger-envelope dd8b368 Reword the header regarding the envelope 357fe25 Add message envelope in the documentation
* 4.1: Simplified the "Release Process" page [Workflow] Fix typo documentation Fix mismatched list items typos in sample code [symfony#9988] fix minor typos [symfony#10099] update XML and PHP config examples [symfony#9969] fix a minor typo [symfony#10022] fix a minor typo preUpdate Event Listener On Uploaded Imagery [symfony#9757] fix rst syntax [symfony#10124] fix XML attribute name [symfony#10062] fix the code block [PHPUnitBridge] Explain how to show stack traces Fix docs on trusted hosts opcode optimizations
Because we've merged this beautiful PR :)