-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Messenger] multiple failure transports support #34979
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
[Messenger] multiple failure transports support #34979
Conversation
src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
Outdated
Show resolved
Hide resolved
9a7eb40
to
099a646
Compare
93c5188
to
f995ffa
Compare
src/Symfony/Component/Messenger/EventListener/SendFailedMessageToFailureTransportListener.php
Show resolved
Hide resolved
src/Symfony/Component/Messenger/EventListener/SendFailedMessageToFailureTransportListener.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Messenger/EventListener/SendFailedMessageToFailureTransportListener.php
Outdated
Show resolved
Hide resolved
@sroze thanks a lot for the review. |
7ae1176
to
b4f7e61
Compare
22493ed
to
5f3e52f
Compare
5f3e52f
to
98eaef7
Compare
Can someone help me with the review? I was very careful in order to not break any command or any class by extending some classes with more constructor parameters or adding more options to commands (the failed commands). I probably need more tests on the FrameworkBundle (extension part). |
What is missing in this PR? Only Changelog updates? |
252c1ef
to
7b4481a
Compare
@fabpot @weaverryan This PR is ready to be reviewed. I created a symfony project, so anyone can test with my latest changes. |
src/Symfony/Component/Messenger/EventListener/SendFailedMessageToFailureTransportListener.php
Outdated
Show resolved
Hide resolved
$this->assertSame('messenger.transport.'.$expectedFailureTransportsMapping[$transportName], (string) $ref, sprintf('The transport "%s" does not have the expected failed transport reference', $transportName)); | ||
} | ||
|
||
$failedMessageTransportListenerReference = |
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.
Nit pick - this is really a Definition
, not a Reference
$container->getDefinition('console.command.messenger_failed_messages_show') | ||
->replaceArgument(0, $config['failure_transport']); | ||
->replaceArgument(0, $globalFailureReceiver) | ||
->replaceArgument(1, $container->getDefinition($failureTransportsServiceLocatorId)); |
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.
these should be references, right? We don't normally set a Definition directly on an argument. And should it use $failureTransportsServiceLocatorId
or $failureTransportsServiceLocator
- I'm getting lost (this stuff confuses me) in which is which and what should be used.
->replaceArgument(0, $config['failure_transport']); | ||
->replaceArgument(0, $globalFailureReceiver) | ||
->replaceArgument(1, $senderReferences[$config['failure_transport']] ?? null) | ||
->replaceArgument(5, $container->getDefinition($failureTransportsServiceLocator)); |
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.
Same problem here (ish) as below - we should pass a Reference (which $failureTransportsServiceLocator
is), not a Definition.
$container->removeDefinition('console.command.messenger_failed_messages_retry'); | ||
$container->removeDefinition('console.command.messenger_failed_messages_show'); | ||
$container->removeDefinition('console.command.messenger_failed_messages_remove'); | ||
$container->removeDefinition('messenger.failure.send_failed_message_to_failure_transport_listener'); |
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 revert this change to lessen the diff
if ($transport['failure_transport']) { | ||
if (!isset($config['transports'][$transport['failure_transport']])) { | ||
throw new LogicException(sprintf('Invalid Messenger configuration: the failure transport "%s" is not a valid transport or service id.', $transport['failure_transport'])); | ||
} |
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.
Should we be checking for !isset($senderReferences[$transport['failure_transport']])
here instead? That would be consistent with the above code. It's more confusing, but there is the edge case that the failure_transport is not a registered transport, but just a "sender service id"
abstract_arg('failed transports map by transport name'), | ||
]) | ||
->tag('container.service_locator') | ||
|
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 I'm correct in FrameworkExtension
, these won't be needed.
src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php
Outdated
Show resolved
Hide resolved
$definition = $container->getDefinition($failedCommandId); | ||
$definition->replaceArgument(1, $receiverMapping[$definition->getArgument(0)]); | ||
} | ||
} |
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.
Hmm, wait a second. This is subtle. But currently, in FrameworkExtension
, you are populating arg 0 with $senderReferences[$config['failure_transport']]
. But before, we were populating them with receiver references. Even for me, this makes my head spin a bit :P. You could technically have a failure transport "receiver" service but no "sender" service... though this is (at the very least) an edge case. Usually a sender & receiver are a "pair" because you've defined them as a transport. But this doesn't need to be the case.
The situation would be this: I create a ReceiverInterface
service and tag it with messenger.receiver
and alias
my_failure_receiver
. But, I do not actually register this as a transport. Then, at the command line, I use messenger:failure:show --failure-transport=my_failure_receiver
. That is technically legal. And it's even possible (though unlikely) to set up this kind of situation if you're using AMQP (e.g. you actually set up a true failure_transport
called failure1
, but then with custom binding & routing rules, those messages ultimately end up in a queue connected with the custom my_failure_receiver
receiver.
So.... that's why this code was originally here and I think it probably still needs to be. I don't think that's a problem, other than some of the new code in FrameworkExtension
should actually live here.
We've just moved away from |
opened new PR #38468 with 5.x as base |
This is just merged into symfony 5 right? is there any change to make it work on symfony 4.4 without updating the framework? thanks! |
updating the framework... |
Strategy applied
SendFailedMessageToFailureTransportListener
. This way we re-use the same listener.Configuration example
You can test this feature easily on a demo project. Just follow the README.
More information on issue #34911
What needs to be done so this can be merged: