Skip to content

[Messenger] Fix return senders based on the message parents/interfaces #27184

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 1 commit into from
May 10, 2018

Conversation

yceruto
Copy link
Member

@yceruto yceruto commented May 7, 2018

Q A
Branch? 4.1
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets -
License MIT
Doc PR -

foreach ($config['routing'] as $message => $messageConfiguration) {
if ('*' !== $message && !class_exists($message) && !interface_exists($message, false)) {
throw new LogicException(sprintf('Messenger routing configuration contains a mistake: message "%s" does not exist. It needs to match an existing class or interface.', $message));
}
$messageToSenderIdsMapping[$message] = $messageConfiguration['senders'];

According to the code a message interface is supported into routing configuration, but it doesn't work when SendMessageMiddleware gets the mapping senders for the current object message.

This PR tries to fix it.

ogizanagi
ogizanagi previously approved these changes May 7, 2018
@nicolas-grekas
Copy link
Member

I'm not sure this is a good idea, is it?
This is like by-id vs by-type autowiring.
Messages are VO objects, their interface are mostly meaningless to me.

@kbond
Copy link
Member

kbond commented May 7, 2018

I foresee it being a burden to declare all the messages you want sent in your config. This would alleviate that.

@nicolas-grekas
Copy link
Member

But this makes it impossible to opt-out from a handler while implementing an interface or extending a base message class. This feels a lot like global interface-based configuration, which is a no-go.
Creating a new message class should require one to explicitly tell where it should be handled IMHO.

@kbond
Copy link
Member

kbond commented May 7, 2018

Yeah, I understand what you're saying. I have thought of alternative solutions that would work within the current implementation.

@ogizanagi
Copy link
Contributor

But this makes it impossible to opt-out from a handler

That's for senders, not handlers. Also you can opt-out by specifying the specific message class on the routing configuration as classes take precedence over interfaces in SenderLocator.

@nicolas-grekas
Copy link
Member

nicolas-grekas commented May 7, 2018

Putting a 👎 here to prevent merging unless the discussion resolves the issue.

@ogizanagi this is still doing interface-based configuration. It's nice that there is a way to work around it, but that shouldn't be needed at all IMHO. It should be the other way around.

@ogizanagi ogizanagi dismissed their stale review May 7, 2018 18:57

waiting decision

@yceruto
Copy link
Member Author

yceruto commented May 7, 2018

Is the same issue blocker applicable to wildcard '*' option too?

@yceruto
Copy link
Member Author

yceruto commented May 7, 2018

For the record, this is what it would allows:

framework:
    messenger:
        transports:
            amqp: ...
            aws: ...
        routing:
            App\Message\AMQPMessageInterface: amqp
            App\Message\AWSMessageInterface: aws

from here, all my messages that need to be send through amqp transport will implement AMQPMessageInterface and so on. Otherwise, I must configure each new message class within the routing configuration.

@yceruto
Copy link
Member Author

yceruto commented May 7, 2018

But I understand what @nicolas-grekas says too and probably this goal should be reached in another way around...

@nicolas-grekas
Copy link
Member

nicolas-grekas commented May 7, 2018

OK, I get it better now. I'm removing my -1 above, this may actually be a good idea: this is configuration-based already and senders are not bound by messages' interfaces. The issue here is finding which sender to select for a given message, and when no sender is explicitly defined, falling back to interfaces then * should be OK. Sorry for the misunderstanding.

I then have a question: what about parent classes? e.g VarDumper's AbstractCloner checks them before:
https://github.com/symfony/symfony/blob/master/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php#L273

Don't we want to do the same here?

@yceruto yceruto force-pushed the messenger_support_message_interface branch from 966ebb1 to 0ac140a Compare May 7, 2018 22:13
@yceruto
Copy link
Member Author

yceruto commented May 7, 2018

Parent classes supports added.

@yceruto yceruto force-pushed the messenger_support_message_interface branch from 0ac140a to 8b8100c Compare May 7, 2018 22:25
@yceruto yceruto changed the title [Messenger] Fix return senders based on the message interface [Messenger] Fix return senders based on the message parents/interfaces May 7, 2018
@nicolas-grekas
Copy link
Member

We should be clear that this is a fallback: when no sender exists for a given class, we check the parents. One could expect that when a sender is registered for a given interface, it gets all the messages from that type even if a class-specific sender is also configured. Correct ?

App\Message\AMQPMessageInterface: amqp

Note that I feel like this kind of dispatching should be avoided: messages should be independent of the sender that may handle them, isn't it? The interface should be semantic instead, allowing to label message by "kinds", and not by infrastructure component.

@yceruto
Copy link
Member Author

yceruto commented May 7, 2018

We should be clear that this is a fallback: when no sender exists for a given class, we check the parents.

Indeed...

One could expect that when a sender is registered for a given interface, it gets all the messages from that type even if a class-specific sender is also configured. Correct ?

Sorry I'm not sure to understand your statement very well... when a sender is registered for a given interface it's used to send all messages that implement that interface unless exists a class-specific sender also configured for the same message, which probably should be a different sender and the message shouldn't implement that interface. Anyway this is the current order of priority: 'class|parents|interfaces|*': sender_name.

Note that I feel like this kind of dispatching should be avoided: messages should be independent of the sender that may handle them, isn't it?

It's just an example, but I guess it depeds of how many senders you have and how many senders are handling the same kind of messages.

@sroze sroze added the Messenger label May 8, 2018
$container->set('my_amqp_sender', $sender);

$locator = new SenderLocator($container, array(
DummyMessage::class => array(
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you configure it here so that the interface is the first argument of the locator to prove that the parent class takes precedence on the interface?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.


private function getSenderIds($message): array
{
$senderIds = array();
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure you need that variable anymore, you can use returns directly.

Copy link
Member Author

Choose a reason for hiding this comment

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

Indeed.

),
));

$this->assertEquals(array($sender), $locator->getSendersForMessage(new ChildDummyMessage('Hello', array('name' => 'World'))));
Copy link
Contributor

Choose a reason for hiding this comment

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

assertSame for all the occurrences of assertEquals

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.


class ChildDummyMessage extends DummyMessage
{
private $extra;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see you using that extra so I guess it can be removed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed extra code.

@yceruto yceruto force-pushed the messenger_support_message_interface branch 2 times, most recently from 12c0f65 to 88375f5 Compare May 8, 2018 11:19
@yceruto
Copy link
Member Author

yceruto commented May 8, 2018

Status: Needs Review

Copy link
Contributor

@sroze sroze left a comment

Choose a reason for hiding this comment

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

Looks good to me 👍

@yceruto yceruto force-pushed the messenger_support_message_interface branch from 88375f5 to 41e25ab Compare May 9, 2018 19:16
@yceruto
Copy link
Member Author

yceruto commented May 9, 2018

Rebased.

@sroze
Copy link
Contributor

sroze commented May 10, 2018

Thank you @yceruto.

@sroze sroze merged commit 41e25ab into symfony:4.1 May 10, 2018
sroze added a commit that referenced this pull request May 10, 2018
…s/interfaces (yceruto)

This PR was merged into the 4.1 branch.

Discussion
----------

[Messenger] Fix return senders based on the message parents/interfaces

| Q             | A
| ------------- | ---
| Branch?       | 4.1
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

https://github.com/symfony/symfony/blob/c3d4536203981d425adc47552c553a9633186a5e/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php#L1494-L1499

According to the code a message interface is supported into routing configuration, but it doesn't work when `SendMessageMiddleware` gets the mapping senders for the current object message.

This PR tries to fix it.

Commits
-------

41e25ab Fixed return senders based on the message parents/interfaces
@yceruto yceruto deleted the messenger_support_message_interface branch May 10, 2018 15:17
@fabpot fabpot mentioned this pull request May 21, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants