symfony 7 中消息总线需手动启用并配置 transport 与 routing,否则 dispatch() 默认走 sync:// 同步通道;必须在 messenger.yaml 中定义 transport 名称、按消息类 fqcn 配置 routing,并确保消息可序列化,最后清缓存验证。

Symfony 7 中消息总线不是开箱即用的,必须显式启用并按需配置传输与路由,否则所有 dispatch() 都走默认同步通道(sync://),根本不会进队列。
安装与基础启用
Messenger 组件在 Symfony 7 中默认不激活,即使已安装也要手动开启:
- 运行
composer require symfony/messenger安装核心包 - 若用 Doctrine 做队列存储,补装
composer require symfony/doctrine-messenger - 若用 Redis,补装
composer require symfony/redis-messenger - 安装后框架会生成
config/packages/messenger.yaml,但该文件默认是空的或只含注释 —— 你必须手动填内容,否则总线不工作
transport 配置决定消息是否异步
传输(transport)定义消息“存哪、怎么送”,直接决定是立即执行还是进队列。常见错误是只配了 DSN 却没声明 transport 名称:
-
sync://:开发调试用,消息直接调用处理器,无延迟但阻塞 HTTP 请求 -
doctrine://default?queue_name=async:用数据库表当队列,适合轻量级生产环境 -
redis://localhost:6379/messages或amqp://guest:guest@localhost/%2F:RabbitMQ/Redis,推荐生产使用 - 必须在
messenger.yaml的transports:下为每个 DSN 起一个逻辑名(如async),不能只写 DSN - 示例有效配置:
transports:<br> async: '%env(MESSENGER_TRANSPORT_DSN)%'<br> failed: 'doctrine://default?queue_name=failed'
routing 必须指向消息类,不是处理器类
这是最常踩的坑:路由失效导致消息始终同步执行,根本不会进 RabbitMQ 或 Redis。Messenger 只认消息类的完整命名空间(FQCN),不看处理器:
- ✅ 正确写法:
'App\Message\SendEmailNotification': async - ❌ 错误写法:
'App\MessageHandler\SendEmailNotificationHandler': async(完全被忽略) - 未匹配的路由默认走
sync://,不会报错,但行为不符合预期 - 支持命名空间通配:
'App\Message\': async,但注意末尾无反斜杠 - 验证是否生效:运行
php bin/console debug:messenger,输出里必须看到你的消息类 → transport 映射关系
消息类与处理器要能序列化
异步传输要求消息对象能被 PHP 序列化/反序列化,否则 Worker 启动时直接失败:
- 消息类应是纯数据载体,避免在构造函数中传入 Doctrine EntityManager、Logger 等不可序列化对象
- 不要实现
__sleep()或__wakeup()除非你清楚后果;优先用普通属性 + public constructor - 处理器类用
#[AsMessageHandler]标记,方法名任意(通常用__invoke),它本身不参与序列化 - Worker 进程启动命令是
php bin/console messenger:consume async,不是server:run;它独立于 Web 请求生命周期
真正容易被忽略的是:路由配置生效后,必须清除缓存(php bin/console cache:clear)再验证;且 debug:messenger 输出里没看到映射,说明配置没加载或类名大小写/命名空间有偏差——这种问题不会抛异常,只会静默退回到同步模式。











