laravel队列使用速率限制导致一堆超时的问题

有个队列业务使用了限速

class InfoPushQueue implements ShouldQueue
{
  use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

  public $tries = 2;

  public $timeout = 86300;

  /**
   * InfoPushQueue constructor.
   */
  public function __construct()
  {
  }

  /**
   * @throws \Illuminate\Contracts\Redis\LimiterTimeoutException
   */
  public function handle()
  {
    Redis::throttle('key')->allow(2)->every(1)->then(function () {
      //业务
    }, function () {
      return $this->release(10);
    });
  }
}

queue的配置是这样的

'redis' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue' => env('REDIS_QUEUE', 'default'),
    'retry_after' => 86400,
    'block_for' => null,
],

比如有2000个任务在跑
如果我不限速的话 一秒会同时处理10来个,页面加载就慢了,cpu也跑满了,虽然慢但服务器还算是有响应。
然后我想优化下,改成1秒最多处理5个,没想到页面更慢了,cpu依然是跑满,而且服务器会无响应,还不如不限速的情况。
然后我再改小1秒2个,虽然服务器不慢了,但failed_job表会有一堆的超时记录

App\Jobs\InfoPushQueue has been attempted too many times or run too long. The job may have previously timed out.

而且timeout我都设置1天的时间,依然在几分钟后报超时,不知道怎么搞的?
supervisord是这样配的

[program:api]
process_name=%(program_name)s_%(process_num)02d
command=php /home/wwwroot/artisan queue:work redis --daemon --queue=high,default,low,1,2,3,4,5,6,7,8,9 --sleep=3 --tries=2 --backoff=3
autostart=true
autorestart=true
user=root
numprocs=8
redirect_stderr=true
stdout_logfile=/home/wwwroot/storage/logs/worker.log
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 5

换种思路,使用延时队列

delay(Redis::get(‘xxx’))

xxx是Redis取出来的一个未来的unix时间戳,每个时间戳最多delay5次。然后Redis::increase

2年前 评论
www295686243 (楼主) 2年前
  1. supervisordnumprocs 改成 1
  2. tries 是错误重试次数,不是速率限制。
  3. 你这个报错也可能是重试次数过多(次数可能大于tries),不一定是超时。

如果出现重试,那么可以证明队列运行肯定是失败的。
看下日志报错

或者 改成同步测试

QUEUE_CONNECTION=sync

2年前 评论
www295686243 (楼主) 2年前
www295686243 (楼主) 2年前
command=php /home/wwwroot/artisan queue:work redis --daemon --queue=high,default,low,1,2,3,4,5,6,7,8,9 --sleep=3 --tries=2 --backoff=3

并没有发现 supervisor 配置中有定义 timeout 参数

2年前 评论
www295686243 (楼主) 2年前
Hachiko (作者) 2年前
public $tries = 2;

被限速了算tries一次,要么加大要么再优化下业务的逻辑

2年前 评论
www295686243 (楼主) 2年前
AyuAyu 2年前
www295686243 (楼主) 2年前

我这个是每60秒限制2条通过

    public function __construct(Model $dispatch, int $registerStatus, string $action)
    {
        $this->dispatch = $dispatch;
        $this->registerStatus = $registerStatus;
        $this->redisBlock = env('REDIS_BLOCK', 59);
        $this->redisAllow = env('REDIS_ALLOW', 2);
        $this->redisEvery = env('REDIS_EVERY', 60);
        $this->action = $action;
    }

    /**
     * @throws \Illuminate\Contracts\Redis\LimiterTimeoutException
     */
    public function handle(): void
    {
        Redis::throttle('key')->block($this->redisBlock)
            ->allow($this->redisAllow)
            ->every($this->redisEvery)
            ->then(function () {
                $programSiteService = new ProgramSiteService();
                $programSiteService->injectC2($this->dispatch, $this->registerStatus, $this->action);

            }, function () {
                Log::error('获取不了锁');
                return $this->release(3);
            });


    }
2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!