Вы хотите отправлять одно письмо каждые 5 секунд. Одним из простых решений этой проблемы является команда sleep
:
$subscriptions->each(function ($subscription) {
// send email to:
logger($subscription->email);
sleep(5);
});
У этого решения есть существенных недостатков : у вас очень долго выполняемое задание, блокирующее вашу очередь. Кроме того, если это не удается, повторное выполнение этой работы может привести к повторной отправке некоторых писем.
Вместо этого вам нужно задание для каждого подписчика:
// SendDailyNewsletter
public function handle()
{
$subscriptions = DB::table()..;
// for every recipient of your newsletter create a new job
$subscriptions->each(function ($subscription) {
SendDailyNewsletterToSubscriber::dispatch($subscription->email);
});
}
Теперь мы можем использовать Redis :: throttle, чтобы отправлять только одно письмо каждые 5 секунд:
// handle function of SendDailyNewsletterToSubscriber
public function handle()
{
Redis::throttle('key')->allow(1)->every(5)->then(function () {
// send email to subscriber
logger($this->email);
}, function () {
// could not obtain lock, retry this job in 5 seconds.
return $this->release(5);
});
}
Позвольте мне объяснить, что произошло в вашем сценарии: при первой попытке цикла each()
Redis пытается получить блокировку на key
и может получить ее. Во второй итерации (test@example.com) Redis снова пытается получить блокировку, но через 3 секунды она сдается (пропускает письмо). На третьей итерации он может получить блокировку через 2 секунды ...
Вы можете увеличить время ожидания блокировки, используя block()
. Но это решение, по сути, будет таким же, как использование команды sleep()
со всеми недостатками.
$subscriptions->each(function ($subscription) {
logger('+');
Redis::throttle('key')->allow(1)->every(5)->block(5)->then(function () use ($subscription) {
logger($subscription->email);
}, function () {
return $this->release(5);
});
});