Laravel 尝试使用节流时,Redis 上的作业失败

Laravel Jobs fail on Redis when attempting to use throttle

最终目标

我的应用程序的目的是向 Redis 队列发送大量电子邮件(此位正在工作),然后 Redis 将这些电子邮件的处理限制为每隔选定的分钟数仅处理一定数量的电子邮件。

对于这个例子,我有一个将时间附加到文件的测试作业,我试图将它限制为每 60 秒一次。

到目前为止的故事....

到目前为止,我的应用程序已成功将 50 个作业的测试数量推送到 Redis 队列。我可以登录到 Horizo​​n 并在 "processjob" 队列中查看这 50 个作业。我也可以登录redis-cli,在list key下看到50套"queues:processjob".

我的问题是,一旦我尝试打开油门,只有 1 个作业运行,其余作业失败并出现以下错误:

Predis\Response\ServerException: ERR Error running script (call to f_29cc07bd431ccbf64637e5dcb60484560fdfa2da): @user_script:10: WRONGTYPE Operation against a key holding the wrong kind of value in /var/www/html/smhub/vendor/predis/predis/src/Client.php:370

如果我取消节流阀,所有工作文件和 5 个作业立即 运行。

我认为可能是键名不正确,但如果我更改以下内容:

    public function handle()
{
    //
    Redis::throttle('queues:processjob')->allow(1)->every(60)->then(function(){

      Storage::disk('local')->append('testFile.txt',date("Y-m-d H:i:s"));
    }, function (){
      return $this->release(10);
    });
}

对此:

    public function handle()
{
    //
    Redis::funnel('queues:processjob')->limit(1)->then(function(){

      Storage::disk('local')->append('testFile.txt',date("Y-m-d H:i:s"));
    }, function (){
      return $this->release(10);
    });
}

那么一切正常。

我的想法...

有些事情告诉我问题是 redis 键的类型是 "list" 并且作业都在一个列表下。话虽这么说,如果它不是这样工作的,我们将如何限制队列,因为限制需要一个唯一的密钥。

对于在尝试使其正常工作时遇到问题并且遇到与我相同的问题的任何其他人,这就是解决我的问题的方法:

故障

我假设 Redis::throttle('queues:processjob') 是指您想要限制的队列。然而,在重新阅读文档和测试代码之后,我意识到情况并非如此。

修复

Redis::throttle('queues:processjob') 意味着指向它自己的 'holding' 队列,因此必须是唯一的 Redis 键名。因此,将其更改为 Redis::throttle('throttle:queues:processjob') 对我来说效果很好。

工作原理

当我第一次调查这个问题时,我假设 Redis::throttle('this') 限制了您指定的队列。在某种程度上这是正确的,但如果工作是通过其他方式创建的,它将不起作用。

Redis::throttle('this') 实际上创建了一个新的 'holding' 队列,作业将在该队列中运行,直到满足您指定的条件。因此,在此示例中,作业将进入队列 'this',当释放限制触发器时,它们将被传递到在其执行代码中指定的队列。在这种情况下,'queues:processjob'.

希望对您有所帮助!