Search code examples
phpsymfonyqueuehandlermessenger

No configured handlers in Symfony Messenger


I'd like to implement Messenger async handlers and be able to queue some tasks in Redis, but I can't for some reason.

Here is my global config :

  • PHP 7.3.16
  • Symfony 4.4.7
  • Messenger 4.4
  • Redis 5.0.3
  • Predis 1.1

I tried to follow this guide :

https://symfony.com/doc/4.4/messenger.html

Everything is a copy/paste from the doc, except that I replaced my controller with a command.

This dispatch command seems to work :

php bin/console app:dispatch-command

^ Symfony\Component\Messenger\Envelope^ {#5465 -stamps: []
-message: App\Message\SmsNotification^ {#5475 -content: "Look! I created a message!" } }

This command returns no configured handlers :

php bin/console debug:messenger

Messenger

=========

This second command returns an error while trying to consume a message

php bin/console messenger:consume async

TypeError {#174
      #message: "The first argument must be an instance of "Symfony\Component\Messenger\RoutableMessageBus"."
      #code: 0
      #file: "./vendor/symfony/messenger/Command/ConsumeMessagesCommand.php"
      #line: 54
      trace: {
        ./vendor/symfony/messenger/Command/ConsumeMessagesCommand.php:54 { …}
        ./var/cache/dev/ContainerM8fc2IB/srcApp_KernelDevDebugContainer.php:3736 {
          ContainerM8fc2IB\srcApp_KernelDevDebugContainer->getConsole_Command_MessengerConsumeMessagesService()^
          › 
          › $this->privates['console.command.messenger_consume_messages'] = $instance = new \Symfony\Component\Messenger\Command\ConsumeMessagesCommand('', ($this->privates['messenger.receiver_locator'] ?? ($this->privates['messenger.receiver_locator'] = new \Symfony\Component\DependencyInjection\Argument\ServiceLocator($this->getService, [], []))), ($this->services['event_dispatcher'] ?? $this->getEventDispatcherService()), ($this->privates['monolog.logger.messenger'] ?? $this->getMonolog_Logger_MessengerService()), []);
          › 
          arguments: {
            $routableBus: ""
            $receiverLocator: Symfony\Component\DependencyInjection\Argument\ServiceLocator {#178 …}
            $eventDispatcher: Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher {#188 …}
            $logger: Symfony\Bridge\Monolog\Logger {#179 …}
            $receiverNames: []
          }
        }
        ./vendor/symfony/dependency-injection/Container.php:450 { …}
        ./vendor/symfony/dependency-injection/Argument/ServiceLocator.php:40 { …}
        ./vendor/symfony/console/CommandLoader/ContainerCommandLoader.php:45 { …}
        ./vendor/symfony/console/Application.php:541 { …}
        ./vendor/symfony/console/Application.php:634 { …}
        ./vendor/symfony/framework-bundle/Console/Application.php:117 { …}
        ./vendor/symfony/console/Application.php:235 { …}
        ./vendor/symfony/framework-bundle/Console/Application.php:83 { …}
        ./vendor/symfony/console/Application.php:147 { …}
        ./bin/console:42 { …}
      }
    }
    2020-04-20T20:08:02+02:00 [critical] Uncaught Error: The first argument must be an instance of "Symfony\Component\Messenger\RoutableMessageBus".

Here are some relevant files...

# .env
MESSENGER_TRANSPORT_DSN=redis://127.0.0.1:6379/messages/?auto_setup=true&serializer=1&stream_max_entries=0&dbindex=0
# config/packages/messenger.yaml
framework:
    messenger:
        transports:
            async: '%env(MESSENGER_TRANSPORT_DSN)%'
        routing:
            'App\Message\SmsNotification': async
# config/services.yaml
parameters:

services:
    _defaults:
        autowire: true
        autoconfigure: true

    App\:
        resource: '../src/*'
        exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'

    App\Controller\:
        resource: '../src/Controller'
        tags: ['controller.service_arguments']
<?php
// src/Message/SmsNotification.php

namespace App\Message;

class SmsNotification
{
    private $content;

    public function __construct(string $content)
    {
        $this->content = $content;
    }

    public function getContent(): string
    {
        return $this->content;
    }
}
<?php
// src/MessageHandler/SmsNotificationHandler.php

namespace App\MessageHandler;

use App\Message\SmsNotification;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;

class SmsNotificationHandler implements MessageHandlerInterface
{
    public function __invoke(SmsNotification $message)
    {
        dump('ok!');
        echo('handler');
    }
}
<?php
// src/Command/DispatchCommand

namespace App\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use App\Message\SmsNotification;
use Symfony\Component\Messenger\MessageBusInterface;

class DispatchCommand extends Command
{
    protected $bus;
    protected static $defaultName = 'app:dispatch-command';

    public function __construct(MessageBusInterface $bus)
    {
        $this->bus = $bus;
    }

    protected function configure()
    {
        $this
            ->setDescription('Dispatch test command')
            ->setHelp('Dispatch test command');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $dispatch = $this->bus->dispatch(new SmsNotification('Look! I created a message!'));
        dump($dispatch);
    }

Can someone please help me?

Cheers!

Update

I tried to manually route my handlers as explained in the doc :

# config/services.yaml
App\MessageHandler\SmsNotificationHandler:
    tags: [messenger.message_handler]

But it changes nothing.

I also checked if my message and message Handler were registered as services, and it is :

php bin/console debug:container App

[70 ] App\Message\SmsNotification

[71 ] App\MessageHandler\SmsNotificationHandler


Solution

  • I still don't know what causes this issue, but I just succeeded to resolve it by installing a whole new Symfony 4.4.7 project and by overwriting it.

    I also figured out that swiftmailer was replaced by mailer, and twig-bundle by twig-pack, but only for new projects, without beeing notice by composer for existing installations (even using composer update/upgrade/recipes. It may be the cause of my problems but I'm not sure.

    Step 1 : create a new Symfony 4.4.7 project

    composer create-project symfony/website-skeleton newProj ^4.4.7
    sudo chown -R $USER:www-data 
    cd /newProj
    

    Step 2 : overwrite with my git project

    git init
    git remote add origin $url_of_clone_source
    git fetch origin
    git checkout -b master --track origin/master
    

    Step 3 : install vendors and replace obsolete dependencies

    composer install
    composer remove symfony/swiftmailer
    composer require symfony/mailer
    composer remove symfony/twig-bundle
    composer require symfony/twig-pack
    

    Step 4 : check messenger

    $ php bin/console debug:messenger
    
    Messenger
    =========
    
    messenger.bus.default
    ---------------------
    
     The following messages can be dispatched:
    
     ---------------------------------------------------------- 
      App\Message\SmsNotification                               
          handled by App\MessageHandler\SmsNotificationHandler  
      Symfony\Component\Mailer\Messenger\SendEmailMessage       
          handled by mailer.messenger.message_handler           
     ----------------------------------------------------------
    

    Here is my actual composer.json file

    {
      "type": "project",
      "license": "proprietary",
      "require": {
        "php": "7.3.*",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "guzzlehttp/guzzle": "^6.5",
        "impulze/intervention-image-bundle": "^1.2",
        "laminas/laminas-code": "^3.4",
        "laminas/laminas-eventmanager": "^3.2",
        "nelmio/api-doc-bundle": "^3.6",
        "predis/predis": "^1.1",
        "sensio/framework-extra-bundle": "^5.1",
        "symfony/asset": "4.4.*",
        "symfony/console": "4.4.*",
        "symfony/dotenv": "4.4.*",
        "symfony/error-handler": "4.4.*",
        "symfony/expression-language": "4.4.*",
        "symfony/flex": "^1.3.1",
        "symfony/form": "4.4.*",
        "symfony/framework-bundle": "4.4.*",
        "symfony/http-client": "4.4.*",
        "symfony/intl": "4.4.*",
        "symfony/mailer": "4.4.*",
        "symfony/messenger": "4.4.*",
        "symfony/monolog-bundle": "^3.1",
        "symfony/orm-pack": "*",
        "symfony/phpunit-bridge": "^5.0",
        "symfony/process": "4.4.*",
        "symfony/security-bundle": "4.4.*",
        "symfony/serializer-pack": "*",
        "symfony/translation": "4.4.*",
        "symfony/twig-pack": "^1.0",
        "symfony/validator": "4.4.*",
        "symfony/web-link": "4.4.*",
        "symfony/webpack-encore-bundle": "^1.7",
        "symfony/yaml": "4.4.*"
      },
      "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.3",
        "sensiolabs/security-checker": "^6.0",
        "symfony/debug-pack": "*",
        "symfony/maker-bundle": "^1.0",
        "symfony/profiler-pack": "*",
        "symfony/test-pack": "*"
      },
      "config": {
        "preferred-install": {
          "*": "dist"
        },
        "sort-packages": true
      },
      "autoload": {
        "psr-4": {
          "App\\": "src/"
        }
      },
      "autoload-dev": {
        "psr-4": {
          "App\\Tests\\": "tests/"
        }
      },
      "replace": {
        "paragonie/random_compat": "2.*",
        "symfony/polyfill-ctype": "*",
        "symfony/polyfill-iconv": "*",
        "symfony/polyfill-php72": "*",
        "symfony/polyfill-php71": "*",
        "symfony/polyfill-php70": "*",
        "symfony/polyfill-php56": "*"
      },
      "scripts": {
        "auto-scripts": {
          "cache:clear": "symfony-cmd",
          "assets:install %PUBLIC_DIR%": "symfony-cmd",
          "security-checker security:check": "script"
        },
        "post-install-cmd": [
          "@auto-scripts"
        ],
        "post-update-cmd": [
          "@auto-scripts"
        ]
      },
      "conflict": {
        "symfony/symfony": "*"
      },
      "extra": {
        "symfony": {
          "allow-contrib": false,
          "require": "4.4.*"
        }
      }
    }