Сповіщення з інтерфейсом ShouldQueue надсилаються у фоні. Важлива деталь реалізації: для кожного отримувача і кожного каналу Laravel ставить в чергу окреме завдання.
Сповіщення з каналами ['mail', 'database', 'slack'] для 1000 користувачів - це 3000 завдань.
Наслідки:
- канали незалежні: якщо Slack недоступний, пошта й запис у базі все одно пройдуть. Повторюватиметься лише завдання Slack;
- порядок не гарантований: запис у базі може з'явитися раніше чи пізніше за лист;
- масові сповіщення створюють сплеск завдань - варто винести їх в окрему чергу.
Різні черги й підключення для каналів:
public function viaQueues(): array
{
return [
'mail' => 'mail',
'slack' => 'notifications-slow',
'database' => 'default',
];
}
Так повільний чи нестабільний канал не затримує швидкі. Аналогічно viaConnections() для різних підключень черги, а withDelay() - для різних затримок по каналах.
Остаточна перевірка у воркері - shouldSend:
public function shouldSend(object $notifiable, string $channel): bool
{
return $this->invoice->fresh()->isUnpaid();
}
Між постановкою в чергу й обробкою можуть минути хвилини (при затримці - години). Нагадування про неоплачений рахунок, який уже оплатили, - типовий баг. shouldSend викликається у воркері окремо для кожного каналу, і false скасовує надсилання.
Транзакції - afterCommit:
$user->notify((new InvoicePaid($invoice))->afterCommit());
Без нього воркер може обробити сповіщення до коміту і не знайти запис або надіслати сповіщення про те, що потім відкотилося.
Збої:
- метод
failed(Throwable $e)на класі сповіщення викликається, коли завдання вичерпало спроби; $tries,backoff(),retryUntil()і middleware завдань (RateLimitedдля API месенджерів) працюють як у звичайних завданнях;- події
NotificationSending(можна скасувати, повернувшиfalse),NotificationSentіNotificationFailed- для аудиту й метрик.
Ідемпотентність: при повторі після тайм-ауту лист чи SMS може піти двічі - провайдер прийняв повідомлення, але відповідь не дійшла. Для критичних каналів зберігайте ID сповіщення (він спільний для всіх каналів одного надсилання) і перевіряйте, чи його вже доставлено.