在处理之前拆分结果行的最佳做法是什么?
What is the best practice for split result rows before process it?
我正在尝试使用 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
分成一些 parts/chunks。但是这样做的最佳做法是什么?它应该使用查询生成器吧?但是我没有那个想法。
是的,您的问题显然在 $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
。
我正在尝试使用 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
分成一些 parts/chunks。但是这样做的最佳做法是什么?它应该使用查询生成器吧?但是我没有那个想法。
是的,您的问题显然在 $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
。