【问题标题】:What is the best practice for split result rows before process it?在处理之前拆分结果行的最佳做法是什么?
【发布时间】:2021-09-20 03:59:47
【问题描述】:

我正在尝试使用 Laravel 框架为超过 10 万封电子邮件创建一个电子邮件冲击波。

我的命令:

public function handle()
{
    $blastId = $this->argument('blast');

    $blast = Blast::find($blastId);
    activity()->performedOn($blast)->log('Blast is sending');
    foreach ($blast->unsentLogs as $log) {
        try {
            Mail::queue((new BlastEmail($log))->onQueue('emails'));
        } catch (Exception $e) {
            activity('send_failed')->performedOn($log->contact)->causedBy($log)->log('Email send failed: '.$e->getMessage());
        }
    }
    $blast->status = 'sent';
    $blast->save();
    activity()->performedOn($blast)->log('Blast is sent');

    return 0;
}

我的爆炸邮件构造:

public function __construct(BlastLog $log)
{
    $contact = $log->contact;
    $blast = $log->blast;
    $this->content = $blast->content;
    $this->content = str_replace('**UNSUB**', 'https://urltounsubscribe.com', $this->content);
    $this->subject = $blast->subject;
    $this->to($contact->email, "Name");
    $this->from($blast->from_email, $blast->from_name);
    $log->sent_at = now();
    $log->save();
}

我的代码可以在 30 秒内处理不到 1000 封电子邮件,但为什么发送大约 10 万封电子邮件需要很长时间?处理 100k 封邮件应该只需要 3000 秒,但已经超过 3 小时,仍未完成。如何改进我的代码?

我认为问题出在$blast->unsentLogs,它有超过 100k 的集合行,需要大量的 RAM。

也许我需要将$blast->unsentLogs 拆分为一些部分/块。但是这样做的最佳实践是什么?它应该使用查询生成器吗?但我不知道这样做。

【问题讨论】:

    标签: laravel eloquent chunks


    【解决方案1】:

    是的,您的问题显然在$blast->unsentLogs 中。 PHP 无法处理 100k collections,这简直是地狱......

    您应该chunk 结果而不是一次获得所有结果...

    你的代码应该是这样的:

    public function handle()
    {
        $blastId = $this->argument('blast');
    
        $blast = Blast::find($blastId);
        activity()->performedOn($blast)->log('Blast is sending');
        $blast->unsentLogs()->chunk(100, function (Collection $logs) {
            foreach ($logs as $log) {
                try {
                    Mail::queue((new BlastEmail($log))->onQueue('emails'));
                } catch (Exception $e) {
                    activity('send_failed')->performedOn($log->contact)->causedBy($log)->log('Email send failed: '.$e->getMessage());
                }
            }
        });
        $blast->status = 'sent';
        $blast->save();
        activity()->performedOn($blast)->log('Blast is sent');
    
        return 0;
    }
    

    阅读更多关于chunk的信息。

    【讨论】:

    • 工作就像一个魅力,谢谢。我很久以前就知道chunk 的功能,但从不使用它并在需要时忘记它。哈哈 。顺便说一句,你说PHP cannot handle 100k collections 但实际上可以处理它。我的旧代码活动完成了 4 个小时来处理 10 万次收集。 XD
    • 哈哈哈,我对PHP cannot handle 100k collections 的意思是它无法在所需的时间跨度内处理它,4 小时是很多时间。现在几点了? 10 分钟或更短?
    • 现在处理 250k 数据需要 3 小时,可能还很多,但要好得多,而且只使用少量 RAM。
    猜你喜欢
    • 2010-10-09
    • 1970-01-01
    • 2019-10-07
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-11
    相关资源
    最近更新 更多