-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Messenger] configure bus on transport #34247
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
7fcaa29
to
08bdab1
Compare
src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
Outdated
Show resolved
Hide resolved
08bdab1
to
13fbf63
Compare
|
||
return $this->fallbackBus->dispatch($envelope, $stamps); | ||
/** @var SentToFailureTransportStamp|null $sentToFailureStamp */ | ||
$sentToFailureStamp = $envelope->last(SentToFailureTransportStamp::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.
This part replaces the FailedMessageProcessingMiddleware
and makes sure the correct bus is used for messages consumed from the failure transport (directly or via messenger:failed:retry)
4541e3f
to
083af0a
Compare
d5535bf
to
0361526
Compare
0361526
to
a930c6f
Compare
a930c6f
to
bbb5cb3
Compare
I've only deprecated |
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.
Thanks for another thoughtful PR :).
I've started to review, but I'm hitting an immediate doubt. Currently, I could have 2 buses (command.bus
and event.bus
) and safely dispatch both of those to the same transport... because I don't care about priority and my app is simple and that's good enough for me. But with this PR, wouldn't I need to be careful to make sure that all "commands" are routed to a transport where bus
is set to command.bus
and all events are routed to a transport where bus
is set to event.bus
?
Attaching a bus name to each message is quite powerful: a worker can consume many different messages and each will definitely go through the correct bus. If the main motivation for the PR is to make the BusNameStamp
optional when consuming from an external transport, could we instead leave the BusNameStamp
idea, but add a new default_receive_bus
option to each transport? This would be the transport that would be use if no explicit BusNameStamp
is added. We could even change the behavior to throw an exception of no BusNameStamp
or default_receive_bus
is present (and there is more than one bus) so that you don't accidentally route all external messages to the "default bus".
We can also, of course, make the default_bus
config optional as this PR does - that's kind of a separate "thing" and it seems sensible to me.
Thanks!
->scalarNode('default_bus')->defaultNull()->end() | ||
->scalarNode('default_bus') | ||
->defaultNull() | ||
->info('Bus name that will be used for autowiring MessageBusInterface. When there is only a single bus this happens automatically. With multiple buses you can set this option or use named autowiring based on the bus name or explicit wiring.') |
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.
->info('Bus name that will be used for autowiring MessageBusInterface. When there is only a single bus this happens automatically. With multiple buses you can set this option or use named autowiring based on the bus name or explicit wiring.') | |
->info('Bus name that will be used for autowiring MessageBusInterface. When there is only a single bus this happens automatically. With multiple buses, you can set this option or use named autowiring based on the bus name (or explicit wiring).') |
Mostly, the last part of the sentence was confusing because it was "you can do X, or Y or Z" when really it's mean to read like "you can do X or Y (and Y is really 2 things). Hopefully this is clearer - it's minor regardless.
} | ||
|
||
return $this->fallbackBus->dispatch($envelope, $stamps); | ||
$envelope = $envelope->with(new ReceivedStamp($originalReceiver)); |
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.
This logic does feel a bit unnatural here. For example, all the "sent to failure" stuff is done via an event listener, but then we wire this part of the logic right inside this class. It could still be done as an event listener (to look for the SentToFailureTransportStamp
and then add the ReceivedStamp
, couldn't it? I think the complexity is this doing this part of the process if it were in a different listener:
// in case the original receiver does not exist anymore, use the bus configured for failure transport
But I'm still not convinced this is the right place.
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.
This is actually fixing a bug and a requirement for messenger:failed:retry
to work with multiple buses.
If messages end in the failure transport because messages are missing the BusNameStamp (external) or because developers renamed the bus, then those messages currently cannot be consumed at all from the failure transport because they can never go to the right bus.
By doing these checks in the RoutableMessageBus we can use the configured bus of the original transport.
That is true. But there is actually a use-case for not receiving from the same bus used for sending: #31848 If we keep the BusNameStamp how do you suggest to deal with my argument 2) above? People loose all messages just by renaming the bus and you cannot warn them. Or all messages get dispatched to the default bus which is likely not the right one (and we don't want to force specifying one). |
Hmm, instead of a Or... the user in #31848 might be doing something we don't want to support - and maybe they should handle the received message in the same bus. And then, inside the handler, dispatch another message (which could be handled synchronously) into the "correct" bus.
It's an edge case, but one that, indeed, we should worry about. To be fair, doesn't this PR have the same limitation, at least for the failure transport? From
That's less of an evil (because it affects less use-cases), but it still seems like we would have the same hole. I could argue that removing a bus, while there are messages in the queue that are "scheduled" to be sent to it is simply something you should not do. After all, users already cannot remove a message class / handler from their app if there are more messages associated with that class that are in the queue. This is maybe the same situation as that? It seems to me that if a bus is missing, handling should fail and it should go into the failure transport so the user can look into it and deal with it. |
|
I'm fine with a better implementation if you can suggest one ;). The goal is simple: if I dispatch a message to Btw, I'm totally cool with adding an additional way for the system to know which bus to use (like an option on the transport that defines the bus to use if no |
What's the status here? I'm sorry I'm not into the topic much so I don't know how to help. |
I'm confident the Symfony Messenger should not promote features that only work (and not even reliable as I pointed out) when dispatching with messenger and consuming with messenger. For anyone who has experience with message queues, such things are just not reasonable and you face big surprises. |
I already faced a problem with It would be great having this in 4.4. It would improve the DX. |
Talking with @weaverryan on Slack, I think we should keep the Following this reasoning, it would make sense to me to allow binding a bus to a receiver - and this should be optional. When the stamp and the receiver don't match for the bus, we would need to decide for the best behavior: receiver wins, stamp wins, log, exception? Anyway, I think it's too late to resolve this completly before 4.4/5.0 |
The main problem of the BusNameStamp to me is
IMO there should not be a default solution that allows people to fall into this unexpected and non-obvious trap. And if we keep this as default default behavior, I also don't see how to fix #32030. As I don't have time to work on this PR to make a potential compromise, let's just postpone it. Maybe we can some up with a solution later. |
Closing then for now. |
any plans to continue with this? |
Not at the moment |
ReceivedStamp
(andSentToFailureTransportStamp
) to do the routing. This way we can get rid ofBusNameStamp
and several middlewares.This is why explicitly setting the bus on the transport seems like the best solution.
bus
option on the transport which fixes part 3) of [Messenger] make it easier to consume third-party messages #32049. The only thing that changes for people: If you defined more than one bus, you must set the "bus" config option on the transport. Messages received from this transport will be dispatched to this bus automatically. This replaces the--bus
option ofmessenger:consume
command and theBusNameStamp
.--bus
option ofmessenger:consume
which was not good: The worker config is usually in supervisor or some other tool independent of messenger code. So you could easily forget to update the worker config there if you changed a bus name and it will not work at all. Or you accidentally dispatch messages to the wrong bus. With the "bus" option it's always in sync and validated on container build instead of at runtime of the worker.BusNameStamp
we don't need to fallback bus inside RoutableMessageBus which was only for external messages or messages dispatched before its introduction for BC. With that we can make thedefault_bus
config optional even when having multiple buses which fixes [Messenger] Why are you forced to specify a "default bus"? #32030 and prevents unwanted autowiring. You can still use it though and is only a requirement forsymfony/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php
Lines 406 to 409 in 68d1b3f
The only thing not handled is [Messenger] Why are you forced to specify a "default bus"? #32030 (comment) but that should be a separate issue. If you used named autowiring there is no problem. It highly depends on the situation and to me we should try to enhance the error message there when autowiring fails due to
MessageBusInterface