简体   繁体   English

如何在Laravel 5.7中对排队的验证和密码重置通知电子邮件进行限速

[英]How to rate limit queued verification and password reset notification emails in laravel 5.7

Issue 问题

Using Laravel 5.7 with Redis, I have gotten the email verification and password reset notifications to queue using the method described in Stephen Mudere's answer in How to send the password reset link via email using queue in laravel 5 , but I cannot figure out how to rate-limit those particular queued notifications. 通过将Laravel 5.7与Redis一起使用,我已经获得了斯蒂芬·穆德雷(Stephen Mudere)的答案中描述的方法将电子邮件验证和密码重置通知排队,该方法在laravel 5如何使用队列通过电子邮件发送密码重置链接 ,但我不知道如何进行评分-限制那些特定的排队通知。 Because my application will send emails for a variety of reasons (not just these two purposes) and my email server is rate-limited to 30 emails per minute, I need to rate-limit everything on an 'email' queue. 因为我的应用程序会出于多种原因(不仅是这两个目的)发送电子邮件,而且我的电子邮件服务器的速率限制为每分钟30封电子邮件,所以我需要对“电子邮件”队列中的所有内容进行速率限制。

Background 背景

Per the Laravel queue documentation , it seems fairly straighforward to do this in a job class in the handle method using 根据Laravel队列文档 ,使用handle方法在作业类中执行此操作似乎很简单

Redis::throttle('key')->allow(10)->every(60)->then(function () {
  // Job logic...
}, function () {
  // Could not obtain lock...

  return $this->release(10);
});

The problem is that I'm not using a job class, but rather a notification. 问题是我不是在使用作业类,而是在使用通知。 For example, for the password reset, I've created the following 例如,对于密码重置,我创建了以下内容

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;
}

which gets invoked from the User model using: 使用以下方法从User模型中调用该方法:

public function sendPasswordResetNotification($token)
{
        $this->notify(new ResetPasswordNotification($token));
}

Approach 途径

I have attempted to solve this by modifying the sendPasswordResetNotification function in the User model: 我试图通过修改用户模型中的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);
    });
}

Note that the values for the throttle are artificially low for testing purposes. 请注意,出于测试目的,节气门的值人为地降低了。 This seems to work partially. 这似乎部分起作用。 In the example above, if I try two successive password resets, the emails both queue and send. 在上面的示例中,如果我尝试了两次连续的密码重置,则电子邮件将同时排队并发送。 When I try to send the third email (exceeding the limit of 2 per minute I've set), I get a BadMethodCallException, "Call to undefined method App\\User::release()" . 当我尝试发送第三封电子邮件(超过我设置的每分钟2个限制)时,出现BadMethodCallException, "Call to undefined method App\\User::release()" I understand that this is because the User model doesn't have a release method, but it comes back to the problem that I'm not sure exactly where or how to use the throttling logic. 我知道这是因为User模型没有释放方法,但是又回到了我不确定确切在哪里或如何使用限制逻辑的问题。 Is there a way to modify this to work, or do I need to take a totally different approach to sending these messages? 有没有一种方法可以修改它以便工作,或者我需要采取一种完全不同的方法来发送这些消息吗?

Update: Alternative approach that fails for a different reason 更新:由于其他原因而失败的替代方法

I switched from using a notification to using a Job so that I could use the Redis::throttle per the documentation. 我从使用通知切换为使用作业,以便可以根据文档使用Redis :: throttle。 To set up the job to queue a message, I used the approach from How to queue Laravel 5.7 "email verification" email sending . 为了设置作业以使消息排队,我使用了如何排队Laravel 5.7“电子邮件验证”电子邮件发送中的方法 This worked fine for sending queued emails. 这样可以很好地发送排队的电子邮件。 I then tried to throttle the jobs going onto the queue. 然后,我试图限制要排入队列的工作。 Here's my complete approach: 这是我完整的方法:

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);
        });
    }
}

These go onto the queue, but then fail. 这些进入队列,但随后失败。 In the stack trace is the following: Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Class 'App\\Jobs\\Redis' not found in /home/vagrant/code/myapp/app/Jobs/QueuedVerifyEmail.php:27 堆栈跟踪中的内容如下: Symfony\\Component\\Debug\\Exception\\FatalThrowableError: Class 'App\\Jobs\\Redis' not found in /home/vagrant/code/myapp/app/Jobs/QueuedVerifyEmail.php:27

I can't figure out why it's looking for the Redis facade in App\\Jobs when I have a use statement to define the correct location. 当我有一个use语句来定义正确的位置时,我不知道为什么要在App \\ Jobs中寻找Redis外观。

I got it working 我知道了

The solution under "Update: Alternative approach" ended up working. “更新:替代方法”下的解决方案最终起作用。 I'm not sure why it was failing (perhaps something was cached?), but it now appears to work correctly. 我不确定为什么它会失败(也许某些东西被缓存了?),但是现在看来它可以正常工作了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM