A Laravel package that prevents notification floods by buffering queued notifications within a time window. When a single notification arrives, it is sent as-is. When multiple notifications of the same type arrive within the window, they are grouped into a single summary notification.
This package can be installed through Composer:
composer require testmonitor/notify-floodgateThe package will register itself automatically via Laravel's package discovery.
Publish the configuration file:
php artisan vendor:publish --tag=floodgate-configThe configuration file is located at config/floodgate.php:
return [
/*
* The number of seconds to wait before flushing a notification buffer.
* During this window, additional notifications of the same type are
* grouped and sent as a single summary.
*/
'delay' => 10,
/*
* Cache store and key prefix used to hold buffered notifications.
* The store must support atomic locks (e.g. Redis, Memcached, database).
*/
'cache' => [
'store' => null,
'prefix' => 'floodgate',
],
];Add the Gateable trait and a middleware method to any queued notification you want to throttle:
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
use TestMonitor\Floodgate\Concerns\Gateable;
use TestMonitor\Floodgate\Middleware\ThrottlesNotifications;
class IssueAssigned extends Notification implements ShouldQueue
{
use Queueable, Gateable;
public function middleware(): array
{
return [new ThrottlesNotifications];
}
// ...
}That's all the setup required. The floodgate will now buffer notifications within the configured delay window and send a summary when the threshold is exceeded.
Implement toSummary on your notification to define what the summary looks like. It receives all buffered notification instances plus the $channels this particular batch was buffered for, and should return a regular notification — write it exactly like any other notification class, with its own via(), toMail(), toArray(), and so on:
use Illuminate\Notifications\Notification;
public function toSummary(array $notifications, array $channels): Notification
{
return new IssueActivitySummary($notifications, $channels);
}use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use TestMonitor\Floodgate\Concerns\SummarizesNotifications;
class IssueActivitySummary extends Notification
{
use SummarizesNotifications;
public function __construct(public array $notifications, public array $channels) {}
public function toMail(mixed $notifiable): MailMessage
{
return (new MailMessage)
->subject('Your issue activity summary')
->line(__(':count issues have been assigned to you', ['count' => count($this->notifications)]))
->action('View Issues', route('issues.index'));
}
public function toArray(mixed $notifiable): array
{
return ['count' => count($this->notifications)];
}
}The SummarizesNotifications trait is optional and just saves you the boilerplate of adding the $notifications/$channels properties and a via() returning $this->channels. Return $channels rather than hardcoding them: each channel is buffered and flushed independently, so toSummary is called once per channel batch, and hardcoding e.g. ['mail', 'database'] would double-send whichever flushes second.
Pass a custom delay in seconds to ThrottlesNotifications to override the configured default:
public function middleware(): array
{
return [new ThrottlesNotifications(delay: 60)];
}By default, a summary is sent whenever more than one notification is buffered. Raise the threshold to allow a number of originals through before switching to a summary:
public function middleware(): array
{
return [new ThrottlesNotifications(threshold: 3)];
}With a threshold of 3, up to three notifications are delivered individually. A fourth within the same window triggers a summary instead.
Send a notification immediately, skipping the buffer entirely, by calling withoutThrottling():
$user->notify((new IssueAssigned($issue))->withoutThrottling());The package contains a full test suite. Run it using:
composer testRefer to CHANGELOG for more information.
Refer to CONTRIBUTING for contributing details.
- Thijs Kok - Lead developer - ThijsKok
- Stephan Grootveld - Developer - Stefanius
- Frank Keulen - Developer - FrankIsGek
The MIT License (MIT). Please see License File for more information.