Symfony 5,通过邮件程序发送多封电子邮件时内存泄漏

Symfony 5, memory leaking when send multiple emails through mailer

我在发送群发邮件时内存泄漏。我需要每月向大约 100 000 名用户发送时事通讯。 它发生在生产环境和开发环境中。

我正在使用:

下面你可以看到我的命令的主要部分来自 execute 方法。

    // Total Users
    $totalRecords = $this->getUserRepository()->count(['newsletter' => true]);

    if ($totalRecords === 0) {
        $output->writeln('No records found');

        return Command::SUCCESS;
    }

    $offers = $this->fetchOffersByType($type);
    $totalOffers = count($offers);

    // Check if we have popular offers
    if ($totalOffers === 0) {
        $output->writeln('No Offers was found');

        return Command::SUCCESS;
    }

    $totalPages = ceil($totalRecords / self::BUFFER_SIZE);

    // Initializing one time and assign to users
    $newsletter = (new Newsletter())
        ->setSentAt(new DateTime())
        ->setType(NewsletterType::MAP[$type]);

    $totalSuccessSent = 0;
    $total = 0;
    for ($page = 1; $page <= $totalPages; $page++) {
        // Get users to who we will send newsletters
        $users = $this->getUserRepository()
            ->findBy(['newsletter' => true], null, self::BUFFER_SIZE, self::BUFFER_SIZE * ($page - 1));

        foreach ($users as $user) {
            $total++;
            if (empty($user->getEmail())) {
                continue;
            }

            if ($this->emailService->sendNewsletter($user, $type, $offers)) {
                $user->addNewsletter($newsletter);

                $this->em->persist($user);
                $totalSuccessSent++;
            }
        }

        $this->em->flush();

        // Make clean up after specific number of users
        if ($total % self::CLEAN_UP_AFTER === 0) {
            $output->writeln('Clean Up');
            $this->em->clear();
            gc_collect_cycles();
        }
    }

基本上我让所有订阅时事通讯并发送 9 个热门优惠的用户。

这篇文章与sendNewsletter有关。

     try {
        $email = (new TemplatedEmail())
            ->from(new Address($this->parameterBag->get('noReplayEmail'), $this->parameterBag->get('noReplayEmailName')))
            ->to($user->getEmail())
            ->priority(Email::PRIORITY_NORMAL)
            ->subject($subject)
            ->htmlTemplate($template)
            ->context([
                'offers' => $offers,
            ]);

        $this->mailer->send($email);

        return true;
    } catch (TransportExceptionInterface | RfcComplianceException | JsonException $e) {
        return false;
    }

经过调查,我确定 $this->mailer->send($email) 是问题所在。 此命令的内存限制为 512,最多可以发送 +- 1500 封电子邮件。

我正在使用 mailgun。 在某些情况下,错误可能会有所不同,但这种错误发生的时间更长:

php.CRITICAL: Fatal Error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 245760 bytes) {"exception":"[object] (Symfony\Component\ErrorHandler\Error\OutOfMemoryError(code: 0): Error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 245760 bytes) at /home/***/vendor/symfony/mime/Encoder/QpContentEncoder.php:36)"}

我还尝试将 MAILER_DSN 用作 null://null 进行测试,这意味着它不会发送电子邮件。发生同样的问题。

我还能做什么?

更新: 通过 Symfony Messages 异步发送电子邮件对我没有帮助。

此问题的一个解决方案是使用异步发送。 例如,您可以使用 Symfony 组件 Messenger(或其他解决方案): https://symfony.com/doc/current/mailer.html#sending-messages-async

此问题已在 Symfony 5.2 中修复。 这是错误的详细信息:https://github.com/symfony/symfony/pull/37712

所以对于所有遇到同样问题的人,请升级您的 symfony。