php - Laravel Redis 队列忽略限制

标签 php laravel redis throttling task-queue

我正在使用 Laravel Horizo​​n 和 Redis,并且我正在尝试限制它。我使用的外部 API 的速率限制为每分钟 100 个请求。我需要提出大约 700 个请求。我进行了设置,以便添加到队列中的每个作业仅在作业本身中执行一个 API 调用。因此,如果我限制队列,我应该能够保持在限制范围内。由于某种原因,没有发生限制,而是超出了队列(当然,这会触发许多 API 错误)。然而, throttle 在本地工作,但不在我的服务器上工作。

我最初试图根据 Laravel 的队列文档进行限制,但只能让它在本地工作,所以我转而尝试 laravel-queue-rate-limit Github 上的包。根据自述文件,我将以下内容添加到我的 queue.php 配置文件中:

'rateLimits' => [
        'default' => [ // queue name
            'allows' => 75, // 75 job
            'every' => 60 // per 60 seconds
        ]
    ],     

出于某种原因,当我在本地 Ubuntu 环境中运行它时,限制可以正常工作,但它在我的服务器(也是 Ubuntu)上不起作用。在服务器上,它只是吹过队列,就好像没有适当的 throttle 一样。

我是否做错了什么,或者可能有更好的方法来处理速率受限的外部 API?

编辑1:

config/horizo​​n.php

    'environments' => [
        'production' => [
            'supervisor-1' => [
                'connection' => 'redis',
                'queue' => ['default'],
                'balance' => 'simple',
                'processes' => 3,
                'tries' => 100,
            ],
        ],

启动大多数作业的句柄之一:

    public function handle()
    {
        $updatedPlayerIds = [];
        foreach ($this->players as $player) {
            $playerUpdate = Player::updateOrCreate(
                [
                    'id' => $player['id'],
                ],
                [
                    'faction_id' => $player['faction_id'],
                    'name' => $player['name'],
                ]
            );

            // Storing id's of records updated
            $updatedPlayerIds[] = $playerUpdate->id;

            // If it's a new player or the player was last updated awhile ago, then get new data!
            if ($playerUpdate->wasRecentlyCreated ||
                $playerUpdate->last_complete_update_at == null ||
                Carbon::parse($playerUpdate->last_complete_update_at)->diffInHours(Carbon::now()) >= 6) {
                Log::info("Updating '{$playerUpdate->name}' with new data", ['playerUpdate' => $playerUpdate]);
                UpdatePlayer::dispatch($playerUpdate);
            } else {
//                Log::debug("Player data fresh, no update performed", ['playerUpdate' => $playerUpdate]);
            }
        }

        //Delete any ID's that were not updated via the API
        Player::where('faction_id', $this->faction->id)->whereNotIn('id', $updatedPlayerIds)->delete();
    }

此外,这是我制作的一个粗略图表,试图说明我如何在短时间内生成多个作业 PHP 文件,尤其是像 updatePlayer() 这样的文件,这些文件通常会在很短的时间内生成。生成了 700 次。

diagram

最佳答案

它看起来像你提到的包(laravel-queue-rate-limit)does not work well与地平线。使用 Laravel 的内置方法可能会更好。
在 Laravel 的队列中,添加 ->block(60) 来匹配 ->every(60) ,这样默认超时就不会在 60 秒之前启动并调用另一个回调。

Redis::throttle('torn-api')->allow(75)->every(60)->block(60)

此外,请考虑将超时和最大重试值添加到 Horizo​​n 的配置(config/horizo​​n.php)。您还可以在作业本身中使用 failed 方法记录任何异常。请参阅this

在 Horizo​​n 的配置中设置 retry_aftertimeout 值。配置中的 retry_after 值应始终大于完成作业所需的时间。并且 timeout 值应比 retry_after 值短几秒。 “这将确保处理给定作业的工作人员始终在重试作业之前被杀死。”看这个issue还有这个point在文档中。

关于php - Laravel Redis 队列忽略限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62617323/

相关文章:

php - sql - 子查询计算分数

php - 如何将 JavaScript 变量传递给 PHP?

javascript - 如何使用jquery正确加载php文件

laravel - 用新的格式化数组替换相关的模型集合数组

node.js - 如何让 Go 应用程序等待 Redis 列表中的数据可用?

php - 我可以在 Drupal 中编写自己的 HTML 代码吗?

php - 如何在 Laravel 中使用 Sentry 和 Ardent?

Redis:使用 lua 和并发事务

serialization - 使用 ServiceStack Redis/TextSerializer 序列化父类字段

laravel - Access-Control-Allow-Headers 不允许请求 header 字段 X-CSRF-TOKEN