速率限制PHP函数

速率限制PHP函数,php,laravel,webhooks,throttling,Php,Laravel,Webhooks,Throttling,我有一个php函数,当有人访问POST www.example.com/webhook时会调用它。然而,我无法控制的外部服务有时会连续两次快速调用此url,这打乱了我的逻辑,因为webhook会在数据库中保存内容,这需要几毫秒才能完成 换句话说,当第二个请求出现时,不能忽略,第一个请求可能尚未完成,但是我需要按照它出现的顺序完成 因此,我在Laravel中创建了一个小黑客程序,它应该在5秒之间限制执行。它似乎大部分时间都有效。然而,我的代码中的一个错误或其他一些疏忽并不能使这个解决方案每次都能工

我有一个php函数,当有人访问POST www.example.com/webhook时会调用它。然而,我无法控制的外部服务有时会连续两次快速调用此url,这打乱了我的逻辑,因为webhook会在数据库中保存内容,这需要几毫秒才能完成

换句话说,当第二个请求出现时,不能忽略,第一个请求可能尚未完成,但是我需要按照它出现的顺序完成

因此,我在Laravel中创建了一个小黑客程序,它应该在5秒之间限制执行。它似乎大部分时间都有效。然而,我的代码中的一个错误或其他一些疏忽并不能使这个解决方案每次都能工作

function myWebhook() {
    // Check if cache value (defaults to 0) and compare with current time.
    while(Cache::get('g2a_webhook_timestamp', 0) + 5 > Carbon::now()->timestamp) {
        // Postpone execution.
        sleep(1);
    }
    // Create a cache value (file storage) that stores the current 
    Cache::put('g2a_webhook_timestamp', Carbon::now()->timestamp, 1);
    // Execute rest of code ...
}

任何人都可能得到了解决这个问题的无懈可击的解决方案?

您基本上设计了自己的简化队列系统,这是正确的方法,但您可以利用本机Laravel队列为您的问题提供更强健的解决方案

定义作业,例如:ProcessWebhook 当收到POST请求以/webhook对作业进行排队时 laravel队列工作者将按照接收到的顺序一次[1]处理一个作业,确保无论接收到多少个请求,都将按顺序逐个处理它们

这项计划的实施情况如下:

,例如:php artisan make:job ProcessWebhook 将webhook处理代码移动到作业的handle方法中,例如:

public function __construct($data)
{
    $this->data = $data;
}

public function handle()
{
    Model::where('x', 'y')->update([
        'field' => $this->data->newValue
    ]);
}
修改Webhook控制器,以便在收到POST请求时分派新作业,例如:

public function webhook(Request $request)
{
    $data = $request->getContent();
    ProcessWebhook::dispatch($data);
}
启动您的队列工作程序php artisan queue:work,它将在后台按照作业到达的顺序运行,一次一个

就是这样,一个可维护的解决方案,可以按顺序逐个处理Webhook。您可以阅读以了解有关可用功能的更多信息,包括重试失败的作业,这可能非常有用


[1] Laravel将为每个工人一次处理一份工作。对于其他用例,您可以添加更多的工作线程以提高队列吞吐量,但在这种情况下,您只需要使用一个工作线程。

我认为数据库锁定会是一个更好的选择。有一次,我编写了一个站点,其中许多人可能可以同时进行事务,但这是不允许的。因此,我在事务数据库中创建了一个名为turns的特殊表,之后我立即为每个会话或用户创建了一个turn,这样一旦达到您的turn,代码就会执行。我用一个while循环和sleep函数来控制它,所以我们对此达成了一致。检查回合的方法是获取按id ASC排序的列表,并限制为1个结果。这将使它更有效率。如果会话或用户id匹配,循环将退出。但记录锁定(也称为数据库锁定)无疑是最好的方法。它与数据库事务有什么关系?我想在Laravelive中寻找一个简单的实现,实际上在另一个应用中也有类似的设置,但是由于CRON的限制,任务以1分钟为增量运行,当您必须等待1分钟执行webhook时,这并不能改善用户体验。因此,在另一个应用程序中,我完成了一个1分钟的任务,每5秒有效地重新检查一次队列,持续1分钟。在此之后,任务将结束并使用CRON再次调用。我将首先研究数据库事务/记录锁定,因为我认为这可能更容易解决问题。@Laravel队列工作程序不是作为cron作业运行的,而是作为后台作业运行的,它总是在运行,等待新作业,这意味着创建作业和处理作业之间的延迟可以尽可能低。队列工作者在将作业添加到队列后立即处理作业,只要它尚未处理作业。您应该花一些时间阅读文档,因为它正是您需要的功能。您正在考虑任务调度,这与Laravel的功能不同。我的错,您是对的,php artisan队列:工作永远运行,但是我必须与任务调度程序混合使用,因为我在共享托管环境中