Symfony Docker环境Messenger邮件订阅器自动消费失效求助
问题描述
在Docker环境的Symfony项目中,我通过Messenger组件实现邮件异步发送,发送完成后邮件会从messenger_message表移除。为留存已发送邮件记录,开发了事件订阅器:手动执行messenger:consume命令时,订阅器可正常将邮件信息存入指定表;但在Docker的Messenger容器中自动执行该命令时,订阅器完全失效——日志无异常,但邮件记录未留存。
相关代码与配置
事件订阅器代码
class MessengerMessageConsumedSubscriber implements EventSubscriberInterface { private $entityManager; public function __construct(EntityManagerInterface $entityManager) { $this->entityManager = $entityManager; } public static function getSubscribedEvents() { return [ WorkerMessageHandledEvent::class => 'onEmailSent', ]; } public function onEmailSent(WorkerMessageHandledEvent $event) { $message = $event->getEnvelope()->getMessage(); $emailSent = new MessengerMessagesSent(); $emailSent->setFromEmail($message->getMessage()->getHeaders()->get('from')->getBody()[0]->getAddress()); $emailSent->setToEmail($message->getMessage()->getHeaders()->get('to')->getBody()[0]->getAddress()); $emailSent->setSubject($message->getMessage()->getHeaders()->get('subject')->getValue()); $this->entityManager->persist($emailSent); $this->entityManager->flush(); } }
Docker启动命令
sh -c "php-fpm & php bin/console messenger:consume async -vv --time-limit=3600 --failure-limit=10"
messenger.yaml配置
transports: # https://symfony.com/doc/current/messenger.html#transport-configuration async: dsn: '%env(MESSENGER_TRANSPORT_DSN)%' options: use_notify: true check_delayed_interval: 60000 retry_strategy: max_retries: 3 multiplier: 2 delay: 30000 failed: 'doctrine://default?queue_name=failed' sent: 'doctrine://default?queue_name=sent'
解决方案
1. 清除容器内Symfony缓存
容器启动时可能未清除缓存,导致订阅器未被注册。修改启动命令,先清除缓存再启动worker:
sh -c "php bin/console cache:clear --env=prod && php-fpm & php bin/console messenger:consume async -vv --time-limit=3600 --failure-limit=10"
开发环境替换为--env=dev,确保容器内APP_ENV与手动执行时一致。
2. 确认订阅器服务注册
检查services.yaml,确保订阅器被正确标记为事件订阅器:
services: App\EventSubscriber\MessengerMessageConsumedSubscriber: tags: ['kernel.event_subscriber'] autowire: true
若使用自动配置,确保订阅器所在命名空间(如App\EventSubscriber\)在自动扫描路径内。
3. 捕获EntityManager操作异常
容器内可能存在异常被吞噬的情况,在订阅器中添加异常捕获并输出日志:
public function onEmailSent(WorkerMessageHandledEvent $event) { try { $message = $event->getEnvelope()->getMessage(); $emailSent = new MessengerMessagesSent(); $emailSent->setFromEmail($message->getMessage()->getHeaders()->get('from')->getBody()[0]->getAddress()); $emailSent->setToEmail($message->getMessage()->getHeaders()->get('to')->getBody()[0]->getAddress()); $emailSent->setSubject($message->getMessage()->getHeaders()->get('subject')->getValue()); $this->entityManager->persist($emailSent); $this->entityManager->flush(); error_log('邮件记录已保存:' . $emailSent->getId()); } catch (\Exception $e) { error_log('保存邮件记录失败:' . $e->getMessage() . ' | 堆栈:' . $e->getTraceAsString()); } }
挂载容器PHP错误日志到宿主机,查看具体异常信息。
4. 验证容器内数据库连接
确认容器内数据库配置与本地一致:
- 检查容器内
MESSENGER_TRANSPORT_DSN、DATABASE_URL环境变量; - 进入容器执行
php bin/console doctrine:query:sql "SELECT 1",验证数据库连接是否正常。
5. 调整Docker进程启动顺序
当前命令用&后台启动php-fpm,可能导致环境变量未正确加载。调整顺序或用进程管理工具(如supervisor):
sh -c "php bin/console messenger:consume async -vv --time-limit=3600 --failure-limit=10 & php-fpm"
6. 确认Messenger事件分发配置
检查messenger.yaml中总线中间件,确保事件分发未被禁用:
framework: messenger: buses: messenger.bus.default: middleware: - doctrine_persistence - validation - messenger.middleware.dispatch_after_current_bus
内容的提问来源于stack exchange,提问作者Eclip tique
相关产品推荐
相关产品推荐

