使用Yii2 Queue扩展和Postgres 10.4错误“未等待锁”

时间:2019-01-11 11:58:48

标签: php postgresql yii2 queue locking

我在yii2中开发了一个使用yiisoft / yii2-queue扩展的项目。此扩展程序存储订单以导出非常大的CSV。 导出的CSV可以正常工作,但有时会抛出图像异常:https://i.imgur.com/nd4zRrI.png

我认为这可能是因为我使用的postgres版本是:x86_64-pc-linux-gnu上的PostgreSQL 10.4(Debian 10.4-2.pgdg90 +1),由gcc(Debian 6.3.0-18)编译+ deb9u1)6.3.0 20170516,64位

我已经读到它对于9.4版有效。 我拥有的扩展程序的配置如下:

'components' => [
    'queue' => [
        'class' => \yii\queue\db\Queue::class,
        'tableName' => '{{%queue}}', // Table name
        'channel' => 'default', // Queue channel key
        'db' => require(__DIR__ . '/db.php'),
        'mutex' => [
            'class' => \yii\mutex\PgsqlMutex::class,
            'db' => require(__DIR__ . '/db.php'),
        ],
        'mutexTimeout' => 0,
    ],
]

有人知道为什么会发生此错误以及如何解决该错误吗?

2 个答案:

答案 0 :(得分:0)

'mutexTimeout' => 0,

这可能是原因。这意味着该队列将尝试一次获取互斥体,如果失败(在繁忙队列中很有可能),它将抛出此异常。

I added支持PgsqlMutex中的超时,但是尚未发布具有此功能的版本。我建议使用master包的yiisoft/yii2分支并将mutexTimeout设置为非零值。

答案 1 :(得分:0)

通过更改 vendor / yiisoft / yii2-queue / src / drivers / db / Queue.php 中的两种方法来解决此问题-https://github.com/yiisoft/yii2-queue/pull/362/files 代码:

/**
 * @param array $payload
 */
protected function release($payload)
{
    $mutex = $this->mutex->acquire(__CLASS__ . $this->channel, $this->mutexTimeout);

    try {
        if ($this->deleteReleased) {
            $this->db->createCommand()->delete(
                $this->tableName,
                ['id' => $payload['id']]
            )->execute();
        } else {
            $this->db->createCommand()->update(
                $this->tableName,
                ['done_at' => time()],
                ['id' => $payload['id']]
            )->execute();
        }
    } catch (Exception $e) {
        \Yii::error($e->getMessage());
    } finally {
        if ($mutex) {
            $this->mutex->release(__CLASS__ . $this->channel);
        } else {
            \Yii::warning('Queue->release() Has not waited the lock');
        }
    }
}

/**
 * Moves expired messages into waiting list.
 */
private function moveExpired()
{
    if ($this->reserveTime !== time()) {
        $this->reserveTime = time();
        $this->db->createCommand()->update(
            $this->tableName,
            ['reserved_at' => null],
            '[[reserved_at]] < :time - [[ttr]] and [[reserved_at]] is not null and [[done_at]] is null',
            [':time' => $this->reserveTime]
        )->execute();
    }
}