Laravel: отправляйте 1000 писем каждый час, используя очередь - PullRequest
0 голосов
/ 02 ноября 2018

У меня есть таблица пользователей с 5000 записями (5000 пользователей), и на моем сервере я могу просто отправлять 1000 писем каждый час. Как я могу отправлять 1000 писем каждый час, используя очередь? или как заставить очереди спать внутри цикла?

EmailController:

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

SendReminderEmail

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

Ответы [ 2 ]

0 голосов
/ 03 ноября 2018

Laravel имеет встроенную функцию дроссельной заслонки для ограниченных по скорости работ. Из документов :

Если ваше приложение взаимодействует с Redis, вы можете ограничить свою очередь работы по времени или параллелизму. Эта функция может быть полезна, когда Ваши задания в очереди взаимодействуют с API, которые также ограничены по скорости. Например, используя метод газа, вы можете управлять данным типом задания выполнять только 10 раз каждые 60 секунд. Если блокировка не может быть Как правило, вы должны выпустить задание обратно в очередь, чтобы его можно повторить позже:

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 минут, которая применяется к другим работам в очереди (я не уверен в этой части), и в этом случае вам придется прийти с другим решением для проверки, если вы превысили свой предел скорости и выпустить работу обратно в очередь.

0 голосов
/ 02 ноября 2018

Laravel имеет удобную функцию, которая идеально подходит для вашего случая, она называется Планирование задач , вместо того, чтобы перевести задание в спящий режим на один час, вместо этого вы могли бы вызывать его каждый час.

Для этого добавьте расписание работы к методу schedule(), расположенному на App\Console\Kernel, например:

protected function schedule(Schedule $schedule)
{
    $schedule->job(new SendReminderEmail)->hourly();
}

Я бы также порекомендовал вам сделать работу автономной, что значительно упростит эту задачу, я думаю примерно так:

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

    public $event;

    public $users;

    public function __construct()
    {
        $this->users = User::all();

        $this->event = (object)['content' => "Hello Laravel fans",'subject' => 'Test Email'];;
    }

    public function handle()
    {   
        foreach ($this->users as $user) {
            Mail::to($user->email)->queue(new Reminder($this->event));
        }
    }
}

Теперь вы можете просто избавиться от своего контроллера, потому что это задание будет выполняться каждый час автоматически.

Помните, что вам нужно будет запустить cron на вашем сервере, чтобы проверить, нужно ли выполнять задание. Вы также можете запустить его вручную, если вы хотите проверить его, используя php artisan schedule:run.

Надеюсь, это поможет вам.

...