首页 > 解决方案 > Laravel:使用队列每小时发送 1000 封电子邮件

问题描述

我有一个表用户,有 5000 条记录(5000 个用户),在我的服务器中,我每小时只能发送 1000 封电子邮件。我如何使用队列每小时发送 1000 封电子邮件?或者如何让队列在循​​环内休眠?

电子邮件控制器:

class EmailController extends Controller
{
    public function sendEmail(Request $request){

         $event=(object)['content' => "Hello Laravel fans",'subject' => 'Test Email'];
         $users=User::all();
         App\Jobs\SendReminderEmail::dispatch($users,$event)
    }
}

发送提醒电子邮件

class SendReminderEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $event;

    public $email;

    public $users;

    public function __construct($users,$event)
    {
        $this->users = $users;

        $this->event = $event;
    }

    public function handle()
    {   
        foreach ($this->users as $user) {

         Mail::to($user->email)->queue(new Reminder($this->event));
        }
    }
}

标签: laravelqueuejobs

解决方案


Laravel 具有内置的节流功能,用于限速作业。从文档

如果您的应用程序与 Redis 交互,您可能会按时间或并发限制排队的作业。当您的排队作业与同样受速率限制的 API 交互时,此功能可以提供帮助。例如,使用节流方法,您可以节流给定类型的作业,使其每 60 秒仅运行 10 次。如果无法获得锁,您通常应该将作业释放回队列,以便稍后重试:

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

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

在你的情况下,这可能看起来像Redis::throttle(...)->allow(1000)->every(3600)->...

如果您不使用 Redis,另一种可能的特定于排队邮件的解决方案是添加延迟。同样,来自文档

延迟消息队列

如果您希望延迟发送排队的电子邮件,您可以使用该later方法。作为它的第一个参数,该later方法接受一个DateTime指示何时发送消息的实例:

$when = now()->addMinutes(10);

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->later($when, new OrderShipped($order));

使用此方法将要求您在将电子邮件分派到队列的循环期间计算每封电子邮件的延迟。例如,循环的每 1000 次迭代,您可以将延迟增加 1 小时。

如果您使用的是 Amazon SQS 队列服务,则适用于其他排队作业的最大延迟 15 分钟也可能适用于此处(我不确定这部分),在这种情况下,您将不得不提出另一个检查您是否超过速率限制并将作业释放回队列的解决方案。


推荐阅读