Skip to content

[DependencyInjection][Messenger] Unnecessary autoregistration for BatchHandlerInterface #59912

@oneNevan

Description

@oneNevan

Symfony version(s) affected

7.0+

Description

I've faced a scenario, when I want my batch handler to be handling messages only from specific transport, and for that I'm adding corresponding AsMessageHandler attribute with fromTransport option, but when I do so, MessengerPass registers two separate HandlerDescriptors inside the HandlersLocator, as it now has two messenger.message_handler tags (one with from_transport opiton, another - without)

As the result, MyBatchHandler starts consuming MyMessage from any transport, which is not I expected.

How to reproduce

  1. Install symfony/messenger component
  2. Create the following handler and message
<?php

namespace App;

use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\Handler\Acknowledger;
use Symfony\Component\Messenger\Handler\BatchHandlerInterface;

#[AsMessageHandler(fromTransport: 'custom')]
class MyBatchHandler implements BatchHandlerInterface
{
    public function __invoke(MyMessage $message, ?Acknowledger $ack = null): null
    {
        // dummy
        return null;
    }

    public function flush(bool $force): void
    {
        // dummy
    }
}

class MyMessage {
}
  1. Run bin/console debug:container MyBatchHandler and see two messenger.message_handler tags (one expected)
  2. Run bin/console debug:messenger and see there are two handlers for MyMessage class (one expected)

Possible Solution

I'd suggest removing change introduced in PR #44490 and let people add #[AsMessageHandler] attribute manually as recommended for regular handlers - this would be more intuitive for developers IMO

As this is a BC break, it's probably best to introduce this change in symfony/messenger v8.0

As a workaround, it's possible to opt-out from auto-registration for this particular handler and declare handler tag manually:

#config/services.php
<?php

declare(strict_types=1);

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $container, string $env): void {
    $services = $container->services();
    $services->defaults()
        ->autowire()
        ->autoconfigure();
    
    // other autoconfigured services

    $services
        ->set(\App\MyBatchHandler::class)
        ->autoconfigure(autoconfigured: false)
        ->tag('messenger.message_handler', [
            'from_transport' => 'custom',
        ]);
};

Additional Context

Image

bin/console debug:container MyBatchHandler
Image

bin/console debug:messenger
Image

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