Skip to content

[Messenger] Allow handler locator to be set #60753

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

Open
wants to merge 1 commit into
base: 7.4
Choose a base branch
from

Conversation

maxbaldanza
Copy link
Contributor

Hi,

I'd like to use the HandleMessageMiddleware but use a different locator to get the handlers of the messages. The HandleMessageMiddleware uses an interface but I can't see how to define a different implementation as the compiler pass sets this argument per bus.

I could define my own version of the handle_message middleware and provide the dependancy but this means I can no longer use the default_middleware configuration.
By checking if the locator already exists it means the application could define the HandlersLocatorInterface implementation that is used by defining something like this in their services.yaml: {$busName}.messenger.handlers_locator: '@Application\Middleware\HandlersLocator'

Would be great to hear if there's maybe a better way to do this or if I've missed a detail on how to provide the HandlersLocatorInterface

Q A
Branch? 7.4
Bug fix? no
New feature? yes
Deprecations? no
Issues
License MIT

{
$container = $this->getContainerBuilder($busId = 'message_bus');

$container->register($busId. '.messenger.handlers_locator', \stdClass::class);
Copy link
Contributor Author

@maxbaldanza maxbaldanza Jun 10, 2025

Choose a reason for hiding this comment

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

stdClass isn't the right class here but wasn't sure it was worth the effort to create a fake HandlersLocatorInterface but happy to add it if you would prefer

The `HandleMessageMiddleware` has a dependency on a `HandlersLocatorInterface`
but this gets registered by the messenger pass.

As far as I can see there isn't a way for an application to provide it's
own implementation. By checking if the service already exists before
registering then we can allow applications to define their own
@maxbaldanza maxbaldanza force-pushed the change-handlers-locator branch from fcff4ae to 8b63b8f Compare June 10, 2025 19:06
@nicolas-grekas
Copy link
Member

I'm mixed here: a similar change could potentially apply to many compiler passes.
Instead, you could define a compiler pass that runs after the MessengerPass. Did you give it a try?
Also: what prevents you from defining the $handlersLocatorMappingByBus that you need using existing configuration means for Messenger?

@maxbaldanza
Copy link
Contributor Author

I'm mixed here: a similar change could potentially apply to many compiler passes.
Instead, you could define a compiler pass that runs after the MessengerPass. Did you give it a try?

Yeah I think that's a fair comment. I could define a compiler pass to do the same but it'd be great if the Symfony framework provided a way to be able to customise that without a compiler pass given there's an interface there.
Normally if you need to overwrite a service then there isn't the need for a compiler pass and can be done with service configuration.

Also: what prevents you from defining the $handlersLocatorMappingByBus that you need using existing configuration means for Messenger?

My use case isn’t about customising the handler mapping — I want to replace the entire HandlersLocatorInterface implementation. The current setup hardcodes the HandlersLocator class, making it impossible to override cleanly via configuration.

Given Symfony has an interface there then it'd be great to be able to swap out the implementation some way. Open to adjust the approach if there's a preferred pattern

Comment on lines +169 to +170
if (!$container->has($locatorId)) {
$container->register($locatorId, HandlersLocator::class)
Copy link
Member

Choose a reason for hiding this comment

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

Could it be interesting to give the handlers locator to the existing definition?

Suggested change
if (!$container->has($locatorId)) {
$container->register($locatorId, HandlersLocator::class)
($container->hasDefinition($locatorId) ? $container->getDefinition($locatorId) : $container->register($locatorId, HandlersLocator::class))

Copy link
Contributor Author

@maxbaldanza maxbaldanza Jun 19, 2025

Choose a reason for hiding this comment

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

Could be but that means the first argument needs to be always be an array and if a new argument is added in Symfony in the future for the HandlersLocator then it could be classed as a breaking change because the arguments defined at application level would need to match.

For example, say a bool is now needed as a second param and someone has already defined the service with a different argument then you'd end up with an error: Argument #2 ($foo) must be of type string, bool given

I think it's safer with my suggestion but happy to change it if you prefer.

->setArgument(0, $handlersLocatorMappingByBus[$bus] ?? [])
;
}

if ($container->has($handleMessageId = $bus.'.middleware.handle_message')) {
Copy link
Member

Choose a reason for hiding this comment

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

while at it:

Suggested change
if ($container->has($handleMessageId = $bus.'.middleware.handle_message')) {
if ($container->hasDefinition($handleMessageId = $bus.'.middleware.handle_message')) {

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.

3 participants