我在 Laravel7.x 中有如下代码
Mail::queue(new ReportMail($user));
Mail::send(new ReportMail($user));
在 ReportMail 类中,有没有办法知道邮件是否被调用 Mail::send() 或 Mail::queue() ?
我的所有邮件 MailClass 在发送邮件之前都会经过 MailTrait 函数。
在那里我使用了如下的节流功能:
// somewhere in the file - app/Traits/MailTrait.php
Redis::throttle('emails')
->allow(300) // Maximum number of allowed operations
->every(60) // Time period in seconds for the rate limit
->block(60) // Blocking time (seconds) if rate limit is exceeded
->then(
function () use ($mailTemplateObj) {
$this->sendFinalizedMail($mailTemplateObj);
},
function () {
Log::info('Throttling, Too many email requests received!');
}
);
这对于排队的邮件效果很好...但是当队列仍在处理中时触发发送邮件时。不知何故,这会破坏队列并需要重新启动。
所以我需要在我们的MailClass中弄清楚:在ReportMail中,如果邮件是send()或queue(),并避免使用redis::throttle()来处理mail::send()
我可以通过向 ReportMail 类添加一个标志来解决这个问题,但问题是我有关于 300 个这样的邮件类,我需要在每个类中实现,这感觉不是解决这个问题的好方法......
非常感谢你们的任何好主意...... 谢谢。
为了在不单独修改每个 MailClass 的情况下实现此目的,您可以利用 Laravel 事件系统在邮件通过队列发送时设置一个标志。 创建自定义事件类
// app/Events/MailSentEvent.php
namespace App\Events;
use Illuminate\Queue\SerializesModels;
class MailSentEvent
{
use SerializesModels;
public $isQueued;
public function __construct($isQueued)
{
$this->isQueued = $isQueued;
}
}
修改您的 MailTrait 以在发送邮件时调度事件
// app/Traits/MailTrait.php
use App\Events\MailSentEvent;
use Illuminate\Support\Facades\Event;
// ...
public function sendFinalizedMail($mailTemplateObj, $isQueued = false)
{
Redis::throttle('emails')
->allow(300)
->every(60)
->block(60)
->then(
function () use ($mailTemplateObj, $isQueued) {
$this->sendFinalizedMail($mailTemplateObj);
Event::dispatch(new MailSentEvent($isQueued));
},
function () {
Log::info('Throttling, Too many email requests received!');
}
);
}
在 ReportMail 类中,在应用限制之前检查标志
// app/Mail/ReportMail.php
use App\Events\MailSentEvent;
use Illuminate\Support\Facades\Event;
use Illuminate\Mail\Mailable;
class ReportMail extends Mailable
{
public function build()
{
// ...
$isQueued = Event::hasListeners(MailSentEvent::class);
// Use $isQueued to determine if the mail is sent through queue or not
if (!$isQueued) {
Redis::throttle('emails')
->allow(300)
->every(60)
->block(60)
->then(
function () {
$this->sendFinalizedMail($mailTemplateObj);
},
function () {
Log::info('Throttling, Too many email requests received!');
}
);
} else {
$this->sendFinalizedMail($mailTemplateObj, true);
}
}
}
这样,您可以将逻辑集中在 MailTrait 中,并使用事件系统动态设置标志。这减少了单独修改每个 MailClass 的需要。