Php 错误';没有等待锁';使用Yii2队列扩展和Postgres 10.4
我在yii2中开发了一个项目,它使用yiisoft/yii2队列扩展。此扩展存储用于导出非常大的CSV的订单。 导出的CSV工作正常,但有时会抛出映像异常: 我想这可能是因为我使用的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版的文章,它可以工作。 我拥有的扩展配置如下所示:Php 错误';没有等待锁';使用Yii2队列扩展和Postgres 10.4,php,postgresql,yii2,queue,locking,Php,Postgresql,Yii2,Queue,Locking,我在yii2中开发了一个项目,它使用yiisoft/yii2队列扩展。此扩展存储用于导出非常大的CSV的订单。 导出的CSV工作正常,但有时会抛出映像异常: 我想这可能是因为我使用的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版的文章,它可以工作。 我拥有的扩展配置如下所示: 'compo
'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,
],
]
有人知道为什么会发生此错误以及如何修复它吗
这可能就是原因。这意味着队列将尝试获取互斥锁一次,如果失败(在繁忙队列上很可能失败),它将抛出此异常
在
PgsqlMutex
中支持超时,但尚未发布此功能。我建议使用yiisoft/yii2
包的master
分支,并将mutexTimeout
设置为非零值。通过在供应商/yiisoft/yii2队列/src/drivers/db/queue.php中更改两种方法来修复它
代码:
/**
*@param数组$payload
*/
受保护功能释放($payload)
{
$mutex=$this->mutex->acquire($this->channel,$this->mutexTimeout);
试一试{
如果($this->deleteReleased){
$this->db->createCommand()->删除(
$this->tableName,
['id'=>$payload['id']]
)->执行();
}否则{
$this->db->createCommand()->更新(
$this->tableName,
['done_at'=>time()],
['id'=>$payload['id']]
)->执行();
}
}捕获(例外$e){
\Yii::error($e->getMessage());
}最后{
如果($mutex){
$this->mutex->release(_CLASS.$this->channel);
}否则{
\Yii::warning('Queue->release()未等待锁');
}
}
}
/**
*将过期邮件移动到等待列表中。
*/
私有函数moveExpired()
{
如果($this->reserveTime!==time()){
$this->reserveTime=time();
$this->db->createCommand()->更新(
$this->tableName,
['reserved_at'=>null],
“[[reserved_at]]<:time-[[ttr]]和[[reserved_at]]不为空,[[done_at]]为空”,
[':time'=>$this->reserveTime]
)->执行();
}
}
谢谢你的建议。我们一直在测试解决方案。我们删除了mutexTimeout参数,并将其设置为3,但在这两种情况下都会不时出现错误。错误似乎与导出函数无关,因为错误是以“随机”方式发生的。我们将进一步调查,看看是否找到解决方案。欢迎提出任何其他想法。:)如果您有许多排队作业,DB queue可能会非常慢(至少在我的例子中MySQL上是慢的)——如果您有多个工作线程在繁忙的队列上,可能会导致这样的错误。另外,PgsqlMutex
还远远不够完美,因为它并不真正等待锁,它只是多次重试,直到达到超时-如果您运气不好,每次尝试都可能失败,即使有时间帧,是否可以获得锁。您可以试试MysqlMutex,它在这方面应该更可靠。
'mutexTimeout' => 0,
/**
* @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();
}
}