Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Messenger] Defining transport dynamically #38200

Closed
@abarkine

Description

@abarkine

Description
Current implementation forces applications to define which transport(s) to use with a class in configuration file. It would be great if it was possible to dictate transport in business logic.

This might be a common problem for other developers, that's why I thought it would be good to make it part of symfony/messenger instead of overriding a Symfony class in business application.

Example

Before:

framework:
    messenger:
        transports:
            normal_queue: ...
            important_queue: ...
        routing:
            App\Message\SmsNotification': normal_queue
<?php
// comments, trademark, use statements and constructor removed for PR description
namespace Symfony\Component\Messenger\Transport\Sender;

class SendersLocator implements SendersLocatorInterface
{
    public function getSenders(Envelope $envelope): iterable
    {
        $seen = [];

        foreach (HandlersLocator::listTypes($envelope) as $type) {
            foreach ($this->sendersMap[$type] ?? [] as $senderAlias) {
                if (!\in_array($senderAlias, $seen, true)) {
                    if (!$this->sendersLocator->has($senderAlias)) {
                        throw new RuntimeException(sprintf('Invalid senders configuration: sender "%s" is not in the senders locator.', $senderAlias));
                    }

                    $seen[] = $senderAlias;
                    $sender = $this->sendersLocator->get($senderAlias);
                    yield $senderAlias => $sender;
                }
            }
        }
    }
}

After:

<?php
// comments, trademark, use statements and constructor removed for PR description
namespace Symfony\Component\Messenger\Transport\Sender;

class SendersLocator implements SendersLocatorInterface
{
    public function getSenders(Envelope $envelope): iterable
    {
        if ($envelope->all(OverrideSendersStamp::class)) {
            $overrideSendersStamp = $envelope->last(OverrideSendersStamp::class);

            foreach ($overrideSendersStamp->getSenders() as $senderAlias) {
                yield from $this->getSenderFromAlias($senderAlias);
            }
        } else {
            $seen = [];
    
            foreach (HandlersLocator::listTypes($envelope) as $type) {
                foreach ($this->sendersMap[$type] ?? [] as $senderAlias) {
                    if (!\in_array($senderAlias, $seen, true)) {
                        $seen[] = $senderAlias;

                        yield from $this->getSenderFromAlias($senderAlias);
                    }
                }
            }
        }
    }

    private function getSenderFromAlias(string $senderAlias): iterable
    {
        if (!$this->sendersLocator->has($senderAlias)) {
            throw new RuntimeException(sprintf('Invalid senders configuration: sender "%s" is not in the senders locator.', $senderAlias));
        }

        $sender = $this->sendersLocator->get($senderAlias);
        yield $senderAlias => $sender;
    }
}

In applications, developers can use it like below

// This will be in normal_queue
$bus->dispatch(new SmsNotification('...'));

For overridden behaviour:

// This will be in important_queue
$bus->dispatch(new Envelope(new SmsNotification('...'), [
  new OverrideSendersStamp(['important_queue'])
]));

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions