如何在 laravel 5.7 中限制排队验证和密码重置通知电子邮件的速率
How to rate limit queued verification and password reset notification emails in laravel 5.7
问题
将 Laravel 5.7 与 Redis 一起使用,我已经使用 中 Stephen Mudere 的回答中描述的方法将电子邮件验证和密码重置通知排队,但我不知道如何评价-限制那些特定的排队通知。因为我的应用程序会出于各种原因(不仅仅是这两个目的)发送电子邮件,而且我的电子邮件服务器的速率限制为每分钟 30 封电子邮件,所以我需要对 'email' 队列中的所有内容进行速率限制。
背景
根据 Laravel 队列 documentation,在作业 class 中使用
处理方法似乎相当简单
Redis::throttle('key')->allow(10)->every(60)->then(function () {
// Job logic...
}, function () {
// Could not obtain lock...
return $this->release(10);
});
问题是我使用的不是作业 class,而是通知。例如,对于密码重置,我创建了以下
ResetPassword Class
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Auth\Notifications\ResetPassword as ResetPasswordNotification;
class ResetPassword extends ResetPasswordNotification implements ShouldQueue
{
use Queueable;
}
使用以下方法从用户模型调用:
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPasswordNotification($token));
}
方法
我试图通过修改用户模型中的 sendPasswordResetNotification 函数来解决这个问题:
public function sendPasswordResetNotification($token)
{
Redis::throttle('email')->allow(2)->every(60)->then(function () use($token) {
$this->notify(new ResetPasswordNotification($token));
}, function () {
// Could not obtain lock...
return $this->release(10);
});
}
请注意,出于测试目的,节流阀的值人为降低。这似乎部分起作用。在上面的示例中,如果我尝试两次连续的密码重置,电子邮件都会排队并发送。当我尝试发送第三封电子邮件时(超过我设置的每分钟 2 封的限制),我收到 BadMethodCallException,"Call to undefined method App\User::release()"
。我知道这是因为 User 模型没有释放方法,但它又回到了我不确定在何处或如何使用节流逻辑的问题。有没有办法修改它以使其工作,或者我是否需要采用完全不同的方法来发送这些消息?
更新:因不同原因而失败的替代方法
我从使用通知切换到使用作业,以便我可以根据文档使用 Redis::throttle。为了设置作业以对消息进行排队,我使用了 中的方法。这对于发送排队的电子邮件效果很好。然后我试图限制进入队列的作业。这是我的完整方法:
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Support\Facades\Redis;
class QueuedVerifyEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function handle()
{
Redis::throttle('email')->allow(2)->every(60)->then(function () {
$this->user->notify(new VerifyEmail);
}, function() {
return $this->release(10);
});
}
}
这些进入队列,但随后失败。在堆栈跟踪中是以下内容:
Symfony\Component\Debug\Exception\FatalThrowableError: Class 'App\Jobs\Redis' not found in /home/vagrant/code/myapp/app/Jobs/QueuedVerifyEmail.php:27
当我有一个 use 语句来定义正确的位置时,我不明白为什么它在 App\Jobs 中寻找 Redis facade。
我成功了
“更新:替代方法”下的解决方案最终有效。我不确定它为什么会失败(也许有什么东西被缓存了?),但它现在似乎可以正常工作了。
问题
将 Laravel 5.7 与 Redis 一起使用,我已经使用
背景
根据 Laravel 队列 documentation,在作业 class 中使用
处理方法似乎相当简单Redis::throttle('key')->allow(10)->every(60)->then(function () {
// Job logic...
}, function () {
// Could not obtain lock...
return $this->release(10);
});
问题是我使用的不是作业 class,而是通知。例如,对于密码重置,我创建了以下
ResetPassword Class
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Auth\Notifications\ResetPassword as ResetPasswordNotification;
class ResetPassword extends ResetPasswordNotification implements ShouldQueue
{
use Queueable;
}
使用以下方法从用户模型调用:
public function sendPasswordResetNotification($token)
{
$this->notify(new ResetPasswordNotification($token));
}
方法
我试图通过修改用户模型中的 sendPasswordResetNotification 函数来解决这个问题:
public function sendPasswordResetNotification($token)
{
Redis::throttle('email')->allow(2)->every(60)->then(function () use($token) {
$this->notify(new ResetPasswordNotification($token));
}, function () {
// Could not obtain lock...
return $this->release(10);
});
}
请注意,出于测试目的,节流阀的值人为降低。这似乎部分起作用。在上面的示例中,如果我尝试两次连续的密码重置,电子邮件都会排队并发送。当我尝试发送第三封电子邮件时(超过我设置的每分钟 2 封的限制),我收到 BadMethodCallException,"Call to undefined method App\User::release()"
。我知道这是因为 User 模型没有释放方法,但它又回到了我不确定在何处或如何使用节流逻辑的问题。有没有办法修改它以使其工作,或者我是否需要采用完全不同的方法来发送这些消息?
更新:因不同原因而失败的替代方法
我从使用通知切换到使用作业,以便我可以根据文档使用 Redis::throttle。为了设置作业以对消息进行排队,我使用了
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Support\Facades\Redis;
class QueuedVerifyEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function handle()
{
Redis::throttle('email')->allow(2)->every(60)->then(function () {
$this->user->notify(new VerifyEmail);
}, function() {
return $this->release(10);
});
}
}
这些进入队列,但随后失败。在堆栈跟踪中是以下内容:
Symfony\Component\Debug\Exception\FatalThrowableError: Class 'App\Jobs\Redis' not found in /home/vagrant/code/myapp/app/Jobs/QueuedVerifyEmail.php:27
当我有一个 use 语句来定义正确的位置时,我不明白为什么它在 App\Jobs 中寻找 Redis facade。
我成功了
“更新:替代方法”下的解决方案最终有效。我不确定它为什么会失败(也许有什么东西被缓存了?),但它现在似乎可以正常工作了。