Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pyaesoneaungrgn/atomic-locks-middleware
A package designed to ensure that only one request is processed at a time.
https://github.com/pyaesoneaungrgn/atomic-locks-middleware
double-click hacktoberfest laravel middleware
Last synced: 2 months ago
JSON representation
A package designed to ensure that only one request is processed at a time.
- Host: GitHub
- URL: https://github.com/pyaesoneaungrgn/atomic-locks-middleware
- Owner: PyaeSoneAungRgn
- License: mit
- Created: 2023-08-23T23:37:19.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-04-29T22:57:55.000Z (9 months ago)
- Last Synced: 2024-04-29T23:48:13.631Z (9 months ago)
- Topics: double-click, hacktoberfest, laravel, middleware
- Language: PHP
- Homepage:
- Size: 50.8 KB
- Stars: 33
- Watchers: 1
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Atomic Locks Middleware
A package designed to ensure that only one request is processed at a time.
## Installation
```bash
composer require pyaesoneaung/atomic-locks-middleware
```## Usage
By default, the atomic-locks-middleware uses `$request->user()?->id ?: $request->ip()` within atomic locks.
```php
Route::post('/order', function () {
// ...
})->middleware('atomic-locks-middleware');
```If you prefer to implement IP-based locking, you can use `atomic-locks-middleware:ip`.
```php
Route::post('/order', function () {
// ...
})->middleware('atomic-locks-middleware:ip');
```However, you have the flexibility to define `atomic-locks-middleware:{anything}` to customize the locking mechanism according to your preferences.
```php
Route::post('/order', function () {
// ...
})->middleware('atomic-locks-middleware:{anything}');
```You can also pass additional parameters to the middleware for more customization. The available parameters are:
- `{anything} (string)` : Your custom locking mechanism.
- `{lockDuration} (int)` : Duration for which the lock will be held.
- `{canBlock} (bool)` : Whether the request can wait for the lock or not.
- `{blockDuration} (int)` : If waiting is allowed, the maximum duration to wait for the lock.> If no additional parameters are provided, the default values from the config file will be used.
```php
Route::post('/order', function () {
// ...
})->middleware('atomic-locks-middleware:{anything}');Route::post('/purchase', function () {
// ...
})->middleware('atomic-locks-middleware:{anything},60,true,60');Route::post('/payment/process', function () {
// ...
})->middleware('atomic-locks-middleware:{anything},60,false');
```## How Does It Work?
```php
// AtomicLocksMiddleware.phppublic function handle(Request $request, Closure $next, string $option = null, int $lockDuration = null, string $canBlock = null, int $blockDuration = null): Response
{
if (! empty($canBlock)) {
$canBlock = filter_var($canBlock, FILTER_VALIDATE_BOOLEAN);
}$name = match ($option) {
null => $request->user()?->id ?: $request->ip(),
'ip' => $request->ip(),
default => $option
};$name = "{$request->path()}_{$name}";
$lock = Cache::lock(
config('atomic-locks-middleware.lock_prefix') . $name,
$lockDuration ?: config('atomic-locks-middleware.default_lock_duration')
);if (! $lock->get()) {
if (! ($canBlock ?? config('atomic-locks-middleware.can_block'))) {
return response()->json([
'message' => config('atomic-locks-middleware.message'),
], 429);
}try {
$lock->block($blockDuration ?: config('atomic-locks-middleware.default_block_duration'));
} catch (LockTimeoutException) {
$lock->release();return response()->json([
'message' => config('atomic-locks-middleware.block_timeout_error_message'),
], 500);
} catch (Throwable $th) {
$lock->release();return response()->json([
'message' => $th->getMessage(),
], 500);
}
}app()->instance(config('atomic-locks-middleware.instance'), $lock);
return $next($request);
}/**
* Handle tasks after the response has been sent to the browser.
*/
public function terminate(Request $request, Response $response): void
{
$instanceName = config('atomic-locks-middleware.instance');if (app()->bound($instanceName)) {
app($instanceName)->release();
}
}
```The Atomic Locks Middleware uses [Laravel Atomic Locks](https://laravel.com/docs/10.x/cache#atomic-locks) in the background. It initiates a lock at the beginning of the middleware's execution and releases the lock once the response is dispatched to the browser.
## Publish Configuration
Publish the configuration for customization
```bash
php artisan vendor:publish --provider="PyaeSoneAung\AtomicLocksMiddleware\AtomicLocksMiddlewareServiceProvider"
``````php
return ['middleware_name' => 'atomic-locks-middleware',
'middleware_class' => PyaeSoneAung\AtomicLocksMiddleware\AtomicLocksMiddleware::class,'instance' => 'AtomicLocksMiddleware',
'lock_prefix' => 'atomic_locks_middleware_',
'default_lock_duration' => 60,'can_block' => false,
'default_block_duration' => 60, // It's generally recommended to set the block duration to be longer than the lock duration.
'block_timeout_error_message' => 'Timeout: Unable to acquire lock within the specified time.','message' => 'Too Many Attempts',
];```
## Testing
```php
composer test
```