zackaj/laravel-debounce 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

zackaj/laravel-debounce

Composer 安装命令:

composer require zackaj/laravel-debounce

包简介

Debounce jobs ,notifications and artisan commands.

README 文档

README

logo

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 with information like ip address and authenticated user per request.

Table of Contents

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 recorded (occurrence), the execution is delayed by x seconds.

Features

Warning

Debouncing artisan commands requires laravel version >=11

Demo

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

debounce_compressed.mp4
See Code

FileUploaded.php

<?php

namespace App\Notifications;

use App\Models\File;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;

class FileUploaded extends Notification
{
    use Queueable;

    public function __construct(public File $file) {}

    public function via(object $notifiable): array
    {
        return ['database'];
    }

    public function toArray(object $notifiable): array
    {
        return [
            'files' => $this->file->user->files()
                ->where('created_at', '>=', $this->file->created_at)
                ->get(),
        ];
    }
}

DemoController.php

<?php

namespace App\Http\Controllers;

use App\Models\File;
use App\Models\User;
use App\Notifications\FileUploaded;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Notification;
use Zackaj\LaravelDebounce\Facades\Debounce;

class DemoController extends Controller
{
    public function normalNotification(Request $request)
    {
        $user = $request->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

  • PHP >= 8.1
  • Laravel application (>= 10.x)
  • Up and running cache system that supports atomic locks
  • Up and running queue worker

Composer

  composer require zackaj/laravel-debounce

Configuration

Optionally publish the config file:

php artisan vendor:publish --tag=laravel-debounce-config

This will publish config/debounce.php:

return [
    /*
     * When set to false, debouncing is bypassed entirely and jobs, notifications
     * and commands are fired immediately as if debounce was never called.
     */
    'enabled' => env('LARAVEL_DEBOUNCE_ENABLED', true),

    'driver' => 'cache', // the only supported driver for now
];

You can also toggle debouncing via your .env file:

LARAVEL_DEBOUNCE_ENABLED=false

This is useful for local development or testing environments where you want to disable debouncing without changing any code.

Usage

Basic usage

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

Note

you can't access report tracking without extending the package's classes, see Advanced usage.

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: 'app: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:

your existing jobs, notifications and commands must extend:

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

or just generate new ones using the available make commands.

Make commands

  • Notification
php artisan make:debounce-notification TestNotification
  • Job
php artisan make:debounce-job TestJob
  • Command
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

(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

namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Zackaj\LaravelDebounce\DebounceJob;

class Jobless extends DebounceJob implements ShouldQueue
{
    use Dispatchable;

    public function handle(): void
    {
        $this->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

Debounce job

<?php
...
class Jobless extends DebounceJob implements ShouldQueue
{
...
    public function before(): void
    {
        //run before dispatching the job
    }

    public function after(): void
    {
        //run after dispatching the job
    }
}

Debounce notification

You get the $notifiables injected into the hooks.

<?php
...

class FileUploaded extends DebounceNotification
{
...
    public function before($notifiables): void
    {
        //run before sending the notification
    }

    public function after($notifiables): void
    {
        //run after sending the notification
    }
}

Debounce command

Due to limitations, the hook methods must be static.

<?php
...

class Test extends DebounceCommand
{
...
    public static function before(): void
    {
        //run before executing the command
    }

    public static function after(): void
    {
        //run after executing the command
    }

}

Override Timestamp

By default laravel-debounce debounces from the last occurrence happenedAt timestamp

public function getLastActivityTimestamp(): ?Carbon
{
    return $this->getReport()->occurrences->last()->happenedAt;
}

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

Debounce job

<?php
...
class Jobless extends DebounceJob implements ShouldQueue
{
...
    public function getLastActivityTimestamp(): ?Carbon
    {
        return Message::latest()->first()?->seen_at;
    }
}

Debounce notification

You get the $notifiables injected into the method.

<?php
...

class FileUploaded extends DebounceNotification
{
...
    public function getLastActivityTimestamp(mixed $notifiables): ?Carbon
    {
        return $this->file->user->files->latest()->first()?->created_at;
    }
}

Debounce command

Due to limitations, the method must be static.

<?php
...

class Test extends DebounceCommand
{
...
    public static function getLastActivityTimestamp(): ?Carbon
    {
        return User::latest()->first()?->created_at;
    }
}

Bonus CLI Debounce ( Laravel version >= 11.0.0 )

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

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 to see the debouncer live in the queues tab and to debug any failures.

Testing

When running tests, you may want to disable debouncing so jobs, notifications and commands are fired immediately without any debounce logic.

Add this to your phpunit.xml or .env.testing:

LARAVEL_DEBOUNCE_ENABLED=false

Or disable it per test:

public function test_something()
{
    config(['debounce.enabled' => false]);

    // debouncing is bypassed, everything fires immediately
}

Known Issues

1- If you clear / flush the cache, the report tracking and the registered dispatches will be lost.

2- Debouncing artisan commands requires laravel version >=11

Contributing

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

License

MIT

zackaj/laravel-debounce 适用场景与选型建议

zackaj/laravel-debounce 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 55.41k 次下载、GitHub Stars 达 0, 最近一次更新时间为 2024 年 11 月 09 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 zackaj/laravel-debounce 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 zackaj/laravel-debounce 我们能提供哪些服务?
定制开发 / 二次开发

基于 zackaj/laravel-debounce 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 55.41k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 21
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2024-11-09