Laravel worker 处理作业批次时锁定等待超时

Lock wait timeout when Laravel worker processes job batches

我在日志中看到以下错误。

SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction (SQL: select * from job_batches where id = xxx limit 1 for update)

我发现这个查询是在 Laravel 更新数据库中处理的作业数之前进行的。但是不知道为什么会超时(代码在事务内部,所以应该立即释放锁)。

P.S。我使用 Amazon SQS 驱动我的队列

P.S.S.我建议有一些作业没有提交嵌套 Laravel 事务。但是我试着重现了这样的场景,看来这个建议是错误的。

简而言之,是因为一个批次的工作量大。解决方案是将作业以较小的块添加到批处理中(使用 add() 方法)。

出现这个问题是因为在一个交易中发生了两件事(见下面的代码片段):

  1. 数据库中更新的职位总数
  2. 作业被发送到队列(在我的例子中是 Amazon SQS)

关键是作业多的话,第二个语句会花很多时间。并且只要执行了事务就无法提交(并且第一条语句中受影响的行保持锁定状态)。 但是 一旦第一个作业被推送到队列,它就会被工作人员处理。在处理作业工作者尝试更新数据库中的行后,它执行 SELECT ... FOR UPDATE。等到超时发生

这是Laravel代码的对应片段:

$this->repository->transaction(function () use ($jobs, $count) {
    // Statement 1 (the affected row stays locked until transaction is committed)
    $this->repository->incrementTotalJobs($this->id, $count);

    // Statement 2 (can take a lot of time)
    $this->queue->connection($this->options['connection'] ?? null)->bulk(
        $jobs->all(),
        $data = '',
        $this->options['queue'] ?? null
    );
});