symfony messenger 异步需四步闭环:启用messengerbundle、配置传输(如redis/amqp)、定义可序列化消息类、路由精确指向消息类全名;任一缺失则dispatch同步执行。

Symfony Messenger 不是“装了就能异步”,关键在四步闭环:启用 Bundle、配对传输、定义干净消息、路由到消息类全名。跳过任一环节,dispatch() 就会直接同步执行,队列形同虚设。
Bundle 必须显式启用
仅运行 composer require symfony/messenger 不够。MessengerBundle 需手动加载:
- 打开
config/bundles.php,确认含这一行:Symfony\Bundle\MessengerBundle\MessengerBundle::class => ['all' => true] - 若缺失,添加并保存
- 执行
php bin/console debug:bundles | grep Messenger,有输出才表示真正启用
传输层要选对、配通、验准
传输决定消息存哪、怎么取。开发用 Redis 最省事,生产按能力选:
-
Redis(推荐开发/中小项目):
在.env中写:MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages -
AMQP(如 RabbitMQ,适合高可靠生产):
MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages -
Doctrine(仅限低频过渡):需先安装
symfony/doctrine-messenger,再运行迁移建表 - 配完运行
php bin/console messenger:transport:setup-transports,看到Transport "async" is ready!才算成功
消息类必须“纯数据”,禁用实体和闭包
消息不是业务逻辑容器,而是可序列化的数据快照:
- 只允许 int、string、array、DateTimeInterface 等基础类型
- 禁止放入 Doctrine 实体、Repository、闭包、resource、stdClass —— 否则反序列化失败、消费者崩溃
- 正确示例:
new SendWelcomeEmail($userId, $email),只传 ID 和邮箱字符串 - 处理器里再查库:
$user = $this->userRepository->find($message->getUserId())
路由必须精准匹配消息类全名
这是最常出错的环节。routing 的键是你 new 出来的那个类,不是处理器类名:
- ✅ 正确:
App\Message\SendWelcomeEmail: async - ❌ 错误:
App\MessageHandler\SendWelcomeEmailHandler: async或App\Message\: async - 运行
php bin/console debug:messenger查看输出表格中的 Transport 列:
若对应类名显示async,说明路由生效;若为空或为sync,立即检查拼写、命名空间和自动加载
跑起来后,用 php bin/console messenger:consume async 启动消费者,消息就真正进队列、异步执行了。











