Search code examples
phpsymfonymessage-bus

No handler for message "App\Message\Event\EventMessage". (tow separated message buses)


github repo: https://github.com/00if23/symfony-messenger-testcase

Just run bin/console testcase

I need tow separated message buses to use it with different (not compatible) middleware sets. I have two sets of message, middleware and handler class:

CommandMessage -> CommandMessageMiddlware -> CommandMessageHandler
EventMessage -> EventMessageMiddlware -> EventMessageHandler

I make config/packages/messenger.yaml

framework:
    messenger:
        default_bus: command.bus
        buses:
            event.bus:
                middleware:
                    - App\Middleware\EventMessageMiddlware
            command.bus:
                middleware:
                    - App\Middleware\CommandMessageMiddlware

And add to config/services.yaml


services
    ...
    ...
    App\Message\:
        resource: '../src/Message'
        autoconfigure: false

    App\MessageHandler\:
        resource: '../src/MessageHandler'
        autoconfigure: false

    App\MessageHandler\Event\EventMessageHandler:
        autoconfigure: false
        tags: 
            -   name: messenger.message_handler
                bus: event.bus
                handles: App\Message\Event\EventMessage


    App\MessageHandler\Command\CommandMessageHandler:
        autoconfigure: false
        tags: 
            -   name: messenger.message_handler
                bus: command.bus
                handles: App\Message\Command\CommandMessage

The result is:

        // works as expected with CommandMessageMiddlware
        // on default "command.bus"
        $this->bus->dispatch(new CommandMessage()); 

        // BUT! There I have 'No handler for message "App\Message\Event\EventMessage"' 
        $this->bus->dispatch(new EventMessage());

Every time I dispatch any event on non-default message bus, then I have error "No handler for message XXX"

This is messager:debug command:

Messenger
=========

command.bus
-----------

 The following messages can be dispatched:

 ------------------------------------------------------------------------------------------------------ 
  Messages for COMMAND bus                                                                              
  App\Message\Command\CommandMessage                                                      
      handled by App\MessageHandler\Command\CommandMessageHandler (when bus=command.bus)                                                                                             
 ------------------------------------------------------------------------------------------------------ 

event.bus
---------

 The following messages can be dispatched:

 ---------------------------------------------------------------------------------------------------- 
  Messages for EVENT bus                                                                             
  App\Message\Event\EventMessage                                                    
      handled by App\MessageHandler\Event\EventMessageHandler (when bus=event.bus)  
 ---------------------------------------------------------------------------------------------------- 

Solution

  • The MessageBusInterface that you inject in your command is the default message bus of your application. In your case it is the command.bus, which is the reason why dispatching the CommandMessage works in your example.

    The EventMessage must be dispatched via the event message bus. You have to inject the corresponding MessageBusInterface, and use it for dispatching.

    There are multiple ways to inject the different interface. Symfony conveniently binds your buses to variable names. If you inject MessageBusInterface $eventBus you will automatically get the event bus service. MessageBusInterface $commandBus or MessageBusInterface $bus (as the command bus is the default) will give you the command bus. You can check bin/console debug:container for more details.

    I updated your command like that:

    #[AsCommand(
        name: 'testcase',
    )]
    class TestCaseCommand extends Command
    {
        public function __construct(
            private readonly MessageBusInterface $commandBus,
            private readonly MessageBusInterface $eventBus
        )
        {
            parent::__construct();
        }
    
        protected function execute(InputInterface $input, OutputInterface $output): int
        {
            $io = new SymfonyStyle($input, $output);
    
            $this->commandBus->dispatch(new CommandMessage());
            $this->eventBus->dispatch(new EventMessage());
    
            $io->success('Done');
    
            return Command::SUCCESS;
        }
    }
    

    And get the following output:

    ➜  symfony-messenger-testcase git:(main) ✗ bin/console testcase                           
    App\Middleware\Command\CommandMiddleware in effect
    App\MessageHandler\Command\CommandMessageHandler in effect
    App\Middleware\Event\EventMiddleware in effect
    App\MessageHandler\Event\EventMessageHandler in effect
    
                                                                                                                            
     [OK] Done