{"id":22919287,"url":"https://github.com/zackaj/laravel-debounce","last_synced_at":"2026-04-02T18:29:31.752Z","repository":{"id":261974148,"uuid":"885870340","full_name":"zackAJ/laravel-debounce","owner":"zackAJ","description":"a laravel package that gives you a debounce effect on jobs, notifications and artisan commands with a nice report of occurrences.","archived":false,"fork":false,"pushed_at":"2025-02-24T22:15:21.000Z","size":81,"stargazers_count":138,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-06T20:57:19.017Z","etag":null,"topics":["artisan-commands","composer","debounce","laravel","notifications","package","php","queues"],"latest_commit_sha":null,"homepage":"https://packagist.org/packages/zackaj/laravel-debounce","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zackAJ.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-09T16:00:09.000Z","updated_at":"2025-10-06T12:22:30.000Z","dependencies_parsed_at":"2025-01-21T22:22:41.545Z","dependency_job_id":"c6dfc767-1fa8-4c4b-81a5-11626ff280ba","html_url":"https://github.com/zackAJ/laravel-debounce","commit_stats":null,"previous_names":["zackaj/laravel-debounce"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/zackAJ/laravel-debounce","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zackAJ%2Flaravel-debounce","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zackAJ%2Flaravel-debounce/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zackAJ%2Flaravel-debounce/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zackAJ%2Flaravel-debounce/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zackAJ","download_url":"https://codeload.github.com/zackAJ/laravel-debounce/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zackAJ%2Flaravel-debounce/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279011040,"owners_count":26084863,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["artisan-commands","composer","debounce","laravel","notifications","package","php","queues"],"created_at":"2024-12-14T07:11:27.254Z","updated_at":"2026-04-02T18:29:31.740Z","avatar_url":"https://github.com/zackAJ.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"![logo](https://github.com/user-attachments/assets/b30c65c0-f28b-41c9-a231-ad46e6699c8b)\n\n# Laravel debounce  \n_by zackaj_\n\nLaravel-debounce allows you to accumulate / debounce a job, notification or command to avoid spamming your users and your app's queue.\n\nIt also tracks and registers every request occurrence and gives you a nice [report tracking](#report-tracking) with information like `ip address` and `authenticated user` per request.\n\n\n# Table of Contents\n\n- [Introduction](#introduction)\n  - [Features](#features)\n  - [Demo](#demo)\n\n- [Installation](#installation)\n  - [Prerequisites](#prerequisites)\n  - [Composer](#composer)\n  - [Configuration](#configuration)\n\n- [Usage](#usage)\n  - [Basic usage](#basic-usage)\n  - [Advanced usage](#advanced-usage)\n    - [Make commands](#make-commands)\n    - [No facade usage](#no-facade-usage)\n    - [Report Tracking](#report-tracking)\n    - [Before After Hooks](#before-after-hooks)\n    - [Override Timestamp](#override-timestamp)\n\n- [Bonus CLI Debounce](#bonus-cli-debounce)\n- [Debugging And Monitoring](#debugging-and-monitoring)\n- [Testing](#testing)\n- [Known Issues](#known-issues)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Introduction\n\nThis laravel package uses UniqueJobs (atomic locks) and caching to run only one instance of a task in a debounced interval of x seconds delay.\n\nEverytime a new activity is recorded (occurrence), the execution is delayed by x seconds.\n\n### Features\n\n- Debounce Notifications, Jobs and Artisan Commands [Basic usage](#basic-usage) \u0026 [Advanced usage](#advanced-usage)\n- [Report Tracking](#report-tracking)\n- [Bonus CLI Debounce](#bonus-cli-debounce)\n\n\u003e [!WARNING]\n\u003e Debouncing artisan commands requires laravel version \u003e=11\n\n### Demo\n\nA debounced notification to bulk notify users about new uploaded files.\n\nhttps://github.com/user-attachments/assets/b1d5aafd-256d-4f6f-b31a-0d6dc516793b\n\n\n\u003cdetails\u003e\n\u003csummary\u003eSee Code\u003c/summary\u003e\n\nFileUploaded.php\n```php\n\u003c?php\n\nnamespace App\\Notifications;\n\nuse App\\Models\\File;\nuse Illuminate\\Bus\\Queueable;\nuse Illuminate\\Notifications\\Notification;\n\nclass FileUploaded extends Notification\n{\n    use Queueable;\n\n    public function __construct(public File $file) {}\n\n    public function via(object $notifiable): array\n    {\n        return ['database'];\n    }\n\n    public function toArray(object $notifiable): array\n    {\n        return [\n            'files' =\u003e $this-\u003efile-\u003euser-\u003efiles()\n                -\u003ewhere('created_at', '\u003e=', $this-\u003efile-\u003ecreated_at)\n                -\u003eget(),\n        ];\n    }\n}\n\n```\n\nDemoController.php\n```php\n\u003c?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\File;\nuse App\\Models\\User;\nuse App\\Notifications\\FileUploaded;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Notification;\nuse Zackaj\\LaravelDebounce\\Facades\\Debounce;\n\nclass DemoController extends Controller\n{\n    public function normalNotification(Request $request)\n    {\n        $user = $request-\u003euser();\n        $file = File::factory()-\u003ecreate(['user_id' =\u003e $user-\u003eid]);\n        $otherUsers = User::query()-\u003ewhereNot('id', $user-\u003eid)-\u003eget();\n\n        Notification::send($otherUsers, new FileUploaded($file));\n\n        return back();\n    }\n\n    public function debounceNotification(Request $request)\n    {\n        $user = $request-\u003euser();\n        $file = File::factory()-\u003ecreate(['user_id' =\u003e $user-\u003eid]);\n        $otherUsers = User::query()-\u003ewhereNot('id', $user-\u003eid)-\u003eget();\n\n        Debounce::notification(\n            notifiables: $otherUsers,\n            notification:new FileUploaded($file),\n            delay: 5,\n            uniqueKey:$user-\u003eid,\n        );\n\n        return back();\n    }\n}\n```\n\u003c/details\u003e\n\n## Installation\n\n### Prerequisites\n- PHP \u003e= 8.1\n- Laravel application (\u003e= 10.x)\n- Up and running cache system that supports [atomic locks](https://laravel.com/docs/11.x/cache#atomic-locks)\n- Up and running [queue worker](https://laravel.com/docs/11.x/queues)\n\n### Composer\n\n```bash\n  composer require zackaj/laravel-debounce\n```\n\n### Configuration\n\nOptionally publish the config file:\n```bash\nphp artisan vendor:publish --tag=laravel-debounce-config\n```\n\nThis will publish `config/debounce.php`:\n```php\nreturn [\n    /*\n     * When set to false, debouncing is bypassed entirely and jobs, notifications\n     * and commands are fired immediately as if debounce was never called.\n     */\n    'enabled' =\u003e env('LARAVEL_DEBOUNCE_ENABLED', true),\n\n    'driver' =\u003e 'cache', // the only supported driver for now\n];\n```\n\nYou can also toggle debouncing via your `.env` file:\n```env\nLARAVEL_DEBOUNCE_ENABLED=false\n```\n\nThis is useful for local development or testing environments where you want to disable debouncing without changing any code.\n\n## Usage\n\n### Basic usage\nYou can debounce existing jobs, notifications and commands with zero setup.\n\n\u003e [!NOTE]\n\u003e you can't access [report tracking](#report-tracking) without extending the package's classes, see [Advanced usage](#advanced-usage).\n\n```php\nuse Zackaj\\LaravelDebounce\\Facades\\Debounce;\n\n\n//job\nDebounce::job(\n    job:new Job(),//replace\n    delay:5,//delay in seconds\n    uniqueKey:auth()-\u003euser()-\u003eid,//debounce per Job class name + uniqueKey\n    sync:false, //optional, job will be fired to the queue\n);\n\n//notification\nDebounce::notification(\n    notifiables: auth()-\u003euser(),\n    notification: new Notification(),//replace\n    delay: 5,\n    uniqueKey: auth()-\u003euser()-\u003eid,\n    sendNow: false,\n);\n\n//command\nDebounce::command(\n    command: 'app:command',//replace\n    delay: 5,\n    uniqueKey: $request-\u003eip(),\n    parameters: ['name' =\u003e 'zackaj'],//see Artisan::call() signature\n    toQueue: false,//optional, send command to the queue when executed\n    outputBuffer: null,//optional, //see Artisan::call() signature\n);\n```\n\n## Advanced usage\nIn order to use:\n- [No Facade Usage](#no-facade-usage)\n- [Report Tracking](#report-tracking)\n- [before/after Hooks](#before-after-hooks)\n- [Debounce from custom timestamp](#override-timestamp)\n\nyour existing jobs, notifications and commands must extend:\n\n```php\nuse Zackaj\\LaravelDebounce\\DebounceJob;\nuse Zackaj\\LaravelDebounce\\DebounceNotification;\nuse Zackaj\\LaravelDebounce\\DebounceCommand;\n```\n\nor just generate new ones using the available [make commands](#make-commands).\n\n### Make commands\n\n- Notification\n```bash\nphp artisan make:debounce-notification TestNotification\n```\n\n- Job\n```bash\nphp artisan make:debounce-job TestJob\n```\n\n- Command\n```bash\nphp artisan make:debounce-command TestCommand\n```\n\n### No facade usage\nAlternatively, now you can debounce from the job, notification and command instances directly without using the `Debounce facade` used in [Basic usage](#basic-usage)\n\n```php\n(new Job())-\u003edebounce(...);\n\n(new Notification())-\u003edebounce(...);\n\n(new Command())-\u003edebounce(...);\n```\n\n### Report Tracking\nLaravel-debounce uses the cache to store every request occurrence, use `getReport()` method within your debounceables to access the report chain that has a collection of occurrences.\n\nEvery report will have one occurrence minimum.\n\n```php\n\u003c?php\n\nnamespace App\\Jobs;\n\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Foundation\\Bus\\Dispatchable;\nuse Zackaj\\LaravelDebounce\\DebounceJob;\n\nclass Jobless extends DebounceJob implements ShouldQueue\n{\n    use Dispatchable;\n\n    public function handle(): void\n    {\n        $this-\u003egetReport()-\u003eoccurrences;//collection of occurrences\n        $this-\u003egetReport()-\u003eoccurrences-\u003ecount();\n        $this-\u003egetReport()-\u003eoccurrences-\u003efirst()-\u003ehappenedAt;\n        $this-\u003egetReport()-\u003eoccurrences-\u003efirst()-\u003eip;\n        $this-\u003egetReport()-\u003eoccurrences-\u003efirst()-\u003eips;\n        $this-\u003egetReport()-\u003eoccurrences-\u003efirst()-\u003erequestHeaders;//HeaderBag\n        $this-\u003egetReport()-\u003eoccurrences-\u003efirst()-\u003euser;//authenticated user | null\n    }\n}\n\n```\n\n### Before After Hooks\nIf you wish to run some code before and/or after firing the `debounceables` you can use the available hooks.\n\n**Important:** `after()` hook could run before your `debounceable` is handled if it's `sent to the queue` when:\n- `sendNow==false` and your notification `implements ShouldQueue`\n- `sync==false` and your job `implements ShouldQueue`\n- `toQueue==true` (command)\n\nsee: [Basic usage](#basic-usage)\n\n\n#### Debounce job\n\n```php\n\u003c?php\n...\nclass Jobless extends DebounceJob implements ShouldQueue\n{\n...\n    public function before(): void\n    {\n        //run before dispatching the job\n    }\n\n    public function after(): void\n    {\n        //run after dispatching the job\n    }\n}\n```\n\n#### Debounce notification\nYou get the `$notifiables` injected into the hooks.\n\n```php\n\u003c?php\n...\n\nclass FileUploaded extends DebounceNotification\n{\n...\n    public function before($notifiables): void\n    {\n        //run before sending the notification\n    }\n\n    public function after($notifiables): void\n    {\n        //run after sending the notification\n    }\n}\n```\n\n#### Debounce command\nDue to limitations, the hook methods must be `static`.\n\n```php\n\u003c?php\n...\n\nclass Test extends DebounceCommand\n{\n...\n    public static function before(): void\n    {\n        //run before executing the command\n    }\n\n    public static function after(): void\n    {\n        //run after executing the command\n    }\n\n}\n\n```\n\n### Override Timestamp\nBy default laravel-debounce debounces from the last occurrence `happenedAt` timestamp\n\n```php\npublic function getLastActivityTimestamp(): ?Carbon\n{\n    return $this-\u003egetReport()-\u003eoccurrences-\u003elast()-\u003ehappenedAt;\n}\n```\n\nYou can override this method in your `debounceables` in order to debounce from a custom timestamp of your choice. If `null` is returned the debouncer will fallback to the default implementation above.\n\n#### Debounce job\n\n```php\n\u003c?php\n...\nclass Jobless extends DebounceJob implements ShouldQueue\n{\n...\n    public function getLastActivityTimestamp(): ?Carbon\n    {\n        return Message::latest()-\u003efirst()?-\u003eseen_at;\n    }\n}\n```\n\n#### Debounce notification\nYou get the `$notifiables` injected into the method.\n\n```php\n\u003c?php\n...\n\nclass FileUploaded extends DebounceNotification\n{\n...\n    public function getLastActivityTimestamp(mixed $notifiables): ?Carbon\n    {\n        return $this-\u003efile-\u003euser-\u003efiles-\u003elatest()-\u003efirst()?-\u003ecreated_at;\n    }\n}\n```\n\n#### Debounce command\nDue to limitations, the method must be `static`.\n\n```php\n\u003c?php\n...\n\nclass Test extends DebounceCommand\n{\n...\n    public static function getLastActivityTimestamp(): ?Carbon\n    {\n        return User::latest()-\u003efirst()?-\u003ecreated_at;\n    }\n}\n\n```\n\n## Bonus CLI Debounce ( Laravel version \u003e= 11.0.0 )\nFor fun, you can actually debounce commands from the CLI using the `debounce:command` Artisan command.\n\n```bash\nphp artisan debounce:command 5 uniqueKey app:test\n```\nhere's the signature for the command:\n`php artisan debounce:command {delay} {uniqueKey} {signature*}`\n\n## Debugging And Monitoring\nI recommend using [Laravel telescope](https://laravel.com/docs/11.x/telescope) to see the debouncer live in the queues tab and to debug any failures.\n\n## Testing\n\nWhen running tests, you may want to disable debouncing so jobs, notifications and commands are fired immediately without any debounce logic.\n\nAdd this to your `phpunit.xml` or `.env.testing`:\n```env\nLARAVEL_DEBOUNCE_ENABLED=false\n```\n\nOr disable it per test:\n```php\npublic function test_something()\n{\n    config(['debounce.enabled' =\u003e false]);\n\n    // debouncing is bypassed, everything fires immediately\n}\n```\n\n## Known Issues\n\n1- If you clear / flush the cache, the report tracking and the registered dispatches will be lost.\n\n2- Debouncing artisan commands requires laravel version \u003e=11\n\n\n## Contributing\n\nContributions, issues and suggestions are always welcome! See `contributing.md` for ways to get started.\n\n\n## License\n\n[MIT](https://choosealicense.com/licenses/mit/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzackaj%2Flaravel-debounce","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzackaj%2Flaravel-debounce","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzackaj%2Flaravel-debounce/lists"}