首页 > php > lumen自带的redis queue注意事项
2021
11-13

lumen自带的redis queue注意事项

问题现象:


Illuminate\Queue\MaxAttemptsExceededException/artisan in ?

xxx_queue_name has been attempted too many times or run too long. The job may have previously timed out.

 

1.1 查找reason: 

 1.1.1 报错的job已执行成功,maxTries=1;

 1.1.2 超时时间timeout为600s, 但本次job 开始pop后3s即报上述错误

 1.1.3 一个job 执行了两次,实际上只有一次push ,一次成功一次报错

 1.1.4 运行环境多开了消费者

 1.1.5 不是运行时间超时的,就是 attempts被累加至2,造成上述错误

===========================================================

1.2 复盘下laravel redis queue 执行过程

  1.2.1 从reserved zset 迁移(migrate)retryAfter 时间到期的数据,恢复到正常的主 list

  1.2.2 while(true){ pop from queue list},不断从list 中lpop单个job数据

  1.2.3 同时(luascript)给 reserved zset 备份这个job 数据,并记 attempts +1 ,初始0,此时为1;

  1.2.4 设置定时闹钟alarm信号 ,监控timeout,以便到时处理异常

  1.2.5  run job->fire before event->检查 timeoutAt  和 (maxTries 是否超过attempts)-> run done -> fire after event

2. 问题重现:

   2.1 消费者worker1 pop 了一个job,进行处理, maxtries 为 1,进入 reserved zset ,并且attempt +=1, 此时为1. 

   2.2 消费者1 处理job耗时长,超过 retryfter,默认 60s,但是因为timeout =600s,所以worker1 正常运行;

   2.3 消费者worker2 进入pop流程,将retryfter到期的恢复到正常的queue, 所以刚才的被变相的repush了

   2.4 消费者worker2  pop 了这个job,attempt +=1, 此时为2

   2.5 消费者worker2对数据进行检查 maxTries=1,发现 次数超了, 抛出如上异常,代码如下

/**
     * Mark the given job as failed if it has exceeded the maximum allowed attempts.
     *
     * This will likely be because the job previously exceeded a timeout.
     *
     * @param  string  $connectionName
     * @param  \Illuminate\Contracts\Queue\Job  $job
     * @param  int  $maxTries
     * @return void
     */
    protected function markJobAsFailedIfAlreadyExceedsMaxAttempts($connectionName, $job, $maxTries)
    {
        $maxTries = ! is_null($job->maxTries()) ? $job->maxTries() : $maxTries;

        $timeoutAt = $job->timeoutAt();

        if ($timeoutAt && Carbon::now()->getTimestamp() <= $timeoutAt) {
            return;
        }

        if (! $timeoutAt && ($maxTries === 0 || $job->attempts() <= $maxTries)) {
            return;
        }

        $this->failJob($connectionName, $job, $e = new MaxAttemptsExceededException(
            $job->resolveName().' has been attempted too many times or run too long. The job may have previously timed out.'
        ));

        throw $e;
    }

3. 解决方案,下列任一 ,非and 关系

  3.1 加大timeout同时,加大retryAfter,且 retryAfter>timeout

  3.2 只开启一个worker

  3.3 忽略这个报错^_^


本文》有 0 条评论

留下一个回复