You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 02:46:17