zackaj/laravel-debounce
Debounce Laravel jobs, notifications, and (Laravel 11+) artisan commands to prevent spam and reduce queue load. Uses unique locks and caching to delay execution until activity stops. Tracks each request occurrence with reports including IP and authenticated user.
Installation:
composer require zackaj/laravel-debounce
Publish config (optional):
php artisan vendor:publish --tag=laravel-debounce-config
Basic Usage:
use Zackaj\LaravelDebounce\Facades\Debounce;
Debounce::job(new MyJob(), delay: 5, uniqueKey: auth()->id());
Debounce::notification(
notifiables: User::all(),
notification: new MyNotification(),
delay: 5,
uniqueKey: 'global_key'
);
Debounce::command(
command: 'app:my-command',
delay: 5,
uniqueKey: $request->ip(),
parameters: ['--option' => 'value']
);
First Use Case: Replace immediate notifications/jobs with debounced versions to reduce queue spam (e.g., bulk email sends or rate-limited actions).
Debouncing Jobs:
Debounce::job() for queueable jobs.Zackaj\LaravelDebounce\DebounceJob for custom logic (e.g., hooks, timestamp overrides).class SendWelcomeEmail extends DebounceJob implements ShouldQueue {
public function before(): void {
Log::info('Preparing to send welcome email...');
}
public function handle() {
// Send email logic
}
}
Debouncing Notifications:
Debounce::notification() for bulk notifications.Zackaj\LaravelDebounce\DebounceNotification to access notifiables in hooks.class NewPostNotification extends DebounceNotification {
public function before($notifiables): void {
$this->logActivity($notifiables);
}
}
Debouncing Commands:
Debounce::command() for CLI tasks (Laravel 11+).Zackaj\LaravelDebounce\DebounceCommand for static hooks.php artisan debounce:command 10 user_id app:generate-reports --force
Report Tracking:
$debounceable->getReport()->occurrences.config(['debounce.enabled' => false]) or .env.testing.getLastActivityTimestamp() to debounce based on domain-specific logic (e.g., last message timestamp).Cache Dependencies:
Cache::flush() in production unless necessary.Cache::forget() for specific keys if you need to reset individual debounces.Laravel Version Quirks:
Debounce::command() or the debounce:command Artisan helper.Hook Timing:
after() hooks may run before the debounceable is handled if it’s queued (e.g., ShouldQueue jobs/notifications with sync=false).after() hook fires when the job is dispatched, not when it’s processed.Unique Key Collisions:
uniqueKey is unique per debounceable type (e.g., user_id for notifications, ip for commands).'global' unless intentional.$report = (new MyDebounceJob())->getReport();
dd($report->occurrences->pluck('ip', 'happenedAt'));
public function before(): void {
Log::debug('Debounce triggered', [
'key' => $this->getUniqueKey(),
'occurrences' => $this->getReport()->occurrences->count(),
]);
}
Custom Drivers:
Zackaj\LaravelDebounce\Contracts\DebounceDriver.Dynamic Delays:
getDelay() in your debounceable to calculate delays dynamically:
public function getDelay(): int {
return $this->user->preferences->debounce_delay ?? 5;
}
Event Listeners:
Zackaj\LaravelDebounce\Events\DebounceableDispatched to react to debounced actions:
event(new DebounceableDispatched($debounceable));
CLI Debounce:
Debounce::command('app:command', delay: 10, uniqueKey: 'cli_key');
How can I help you explore Laravel packages today?