Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/zackaj/laravel-debounce

a laravel package that gives you a debounce effect on jobs, notifications and artisan commands with a nice report of occurrences.
https://github.com/zackaj/laravel-debounce

artisan-commands composer laravel notifications package php queues

Last synced: about 2 months ago
JSON representation

a laravel package that gives you a debounce effect on jobs, notifications and artisan commands with a nice report of occurrences.

Awesome Lists containing this project

README

        

![logo](https://github.com/user-attachments/assets/b30c65c0-f28b-41c9-a231-ad46e6699c8b)

# Laravel debounce
_by zackaj_

Laravel-debounce allows you to accumulate / debounce a job,notification or command to avoid spamming your users and your app's queue.

It 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.

# Table of Contents

- [Introduction](#introduction)
- [Features](#features)
- [Demo](#demo)

- [Installation](#installation)
- [Prerequisites](#prerequisites)
- [Composer](#composer)

- [Usage](#usage)
- [Basic usage](#basic-usage)
- [Advanced usage](#advanced-usage)
- [Make commands](#make-commands)
- [No facade usage](#no-facade-usage)
- [Report Tracking](#report-tracking)
- [Before After Hooks](#before-after-hooks)
- [Override Timestamp](#override-timestamp)

- [Bonus CLI Debounce](#bonus-cli-debounce)
- [Debugging And Monitoring](#debugging-and-monitoring)
- [Known Issues](#known-issues)
- [Contributing](#contributing)
- [License](#license)

## Introduction

This laravel package uses UniqueJobs (atomic locks) and caching to run only one instance of a task in a debounced interval of x seconds delay.

Everytime a new activity is recoreded (occurrence), the execution is delayed with x seconds.

### Features

- Debounce Notifications, Jobs and Artisan Commands [Basic usage](#basic-usage) & [Advanced usage](#advanced-usage)
- [Report Tracking](#report-tracking)
- [Bonus CLI Debounce](#bonus-cli-debounce)

### Demo

A debounced notification to bulk notify users about new uploaded files.

https://github.com/user-attachments/assets/b1d5aafd-256d-4f6f-b31a-0d6dc516793b

See Code

FileUploaded.php
```php
$this->file->user->files()
->where('created_at', '>=', $this->file->created_at)
->get(),
];
}
}

```

DemoController.php
```php
user();
$file = File::factory()->create(['user_id' => $user->id]);
$otherUsers = User::query()->whereNot('id', $user->id)->get();

Notification::send($otherUsers, new FileUploaded($file));

return back();
}

public function debounceNotification(Request $request)
{
$user = $request->user();
$file = File::factory()->create(['user_id' => $user->id]);
$otherUsers = User::query()->whereNot('id', $user->id)->get();

Debounce::notification(
notifiables: $otherUsers,
notification:new FileUploaded($file),
delay: 5,
uniqueKey:$user->id,
);

return back();
}
}
```

## Installation

### Prerequisites
- Laravel application (11.x , 10.x should be fine)
- Up and running cache system that supports [atomic locks](https://laravel.com/docs/11.x/cache#atomic-locks)
- Up and running [queue worker](https://laravel.com/docs/11.x/queues)

### Composer

```bash
composer require zackaj/laravel-debounce
```

## Usage

### Basic usage
You can debounce existing jobs, notifications and commands with zero setup.

**Warning** you can't access report or track the requests without extending the package's classes, see [Advanced usage](#advanced-usage)

```php
use Zackaj\LaravelDebounce\Facades\Debounce;

//job
Debounce::job(
job:new Job(),//replace
delay:5,//delay in seconds
uniqueKey:auth()->user()->id,//debounce per Job class name + uniqueKey
sync:false, //optional, job will be fired to the queue
);

//notification
Debounce::notification(
notifiables: auth()->user(),
notification: new Notification(),//replace
delay: 5,
uniqueKey: auth()->user()->id,
sendNow: false,
);

//command
Debounce::command(
command: new Command(),//replace
delay: 5,
uniqueKey: $request->ip(),
parameters: ['name' => 'zackaj'],//see Artisan::call() signature
toQueue: false,//optional, send command to the queue when executed
outputBuffer: null,//optional, //see Artisan::call() signature
);
```

## Advanced usage
In order to use:
- [No Facade Usage](#no-facade-usage)
- [Report Tracking](#report-tracking)
- [before/after Hooks](#before-after-hooks)
- [Debounce from custom timestamp](#override-timestamp)

your existing jobs, notificaitons and commands must extend:

```php
use Zackaj\LaravelDebounce\DebounceJob;
use Zackaj\LaravelDebounce\DebounceNotification;
use Zackaj\LaravelDebounce\DebounceCommand;
```

or just generate new ones using the available [make commands](#make-commands).

### Make commands

- Notification
```bash
php artisan make:debounce-notification TestNotification
```

- Job
```bash
php artisan make:debounce-job TestJob
```

- Command
```bash
php artisan make:debounce-command TestCommand
```

### No facade usage
Alternatively, now you can debounce from the job, notification and command instances directly without using the `Debounce facade` used in [Basic usage](#basic-usage)

```php
(new Job())->debounce(...);

(new Notification())->debounce(...);

(new Command())->debounce(...);
```

### Report Tracking
Laravel-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.

Every report will have one occurrence minimum.

```php
getReport()->occurrences;//collection of occurrences
$this->getReport()->occurrences->count();
$this->getReport()->occurrences->first()->happenedAt;
$this->getReport()->occurrences->first()->ip;
$this->getReport()->occurrences->first()->ips;
$this->getReport()->occurrences->first()->requestHeaders;//HeaderBag
$this->getReport()->occurrences->first()->user;//authenticated user | null
}
}

```

### Before After Hooks
If you wish to run some code before and/or after firing the `debounceables` you can use the available hooks.

**Important:** `after()` hook could run before your `debounceable` is handled if it's `sent to the queue` when:
- `sendNow==false` and your notification `implements ShouldQueue`
- `sync==false` and your job `implements ShouldQueue`
- `toQueue==true` (command)

see: [Basic usage](#basic-usage)

#### Debounce job

```php
getReport()->occurrences->last()->happenedAt;
}
```

You can override this method in your `debounceables` in order to debounce from a custom timestamp of choice, if null returned the debouncer will fallback to the default implementation above.

#### Debounce job

```php
first()?->seen_at;
}
}
```

#### Debounce notification
You get the `$notifiables` injected into the method.

```php
file->user->files->latest()->first()?->created_at;
}
}
```

#### Debounce command
Due to limitations, the method must be `static`.

```php
first()?->created_at;
}
}

```

## Bonus CLI Debounce
For fun, you can actually debounce commands from the CLI using `debounce:command` Artisan command.

```php
php artisan debounce:command 5 uniqueKey app:test
```
here's the signature for the command:
`php artisan debounce:command {delay} {uniqueKey} {signature*}`

## Debugging And Monitoring
I recommend using [Laravel telescope](https://laravel.com/docs/11.x/telescope) to see the debouncer live in queues tab and to debug any failures.

## Known Issues

1- Unique lock gets stuck sometimes when jobs fail [github issue](https://github.com/laravel/framework/issues/37729)

- cause: this happens when deleted models are unserialized causing the job to fail without clearing the lock.

- solution: If you're using `database` cache driver delete the entry from job_locks table.

## Contributing

Contributions, issues and suggestions are always welcome! See `contributing.md` for ways to get started.

## License

[MIT](https://choosealicense.com/licenses/mit/)