Postgres TRUNCATE后跟咨询锁导致死锁(非并发)

时间:2018-08-07 08:28:19

标签: node.js postgresql locking sequelize.js

我试图找出系统锁定中的一些问题,并设置了以下测试,这给了我奇怪的结果。

起初它起作用了。然后,为了避免发生错误时重新运行测试,我将数据库截断从测试结束复制到测试开始,以清除状态开始。

我知道截断和咨询锁可能会死锁,但是最后一个截断应该在请求第一个咨询锁之前完成。

下面是代码和输出。如果按原样运行,它将在释放第一个锁后挂起。如果我在cleanDb块中删除了before,那么代码就很好了。

如果打开顺序记录,则可以看到在我开始创建测试记录之前最后一个截断已完成。

(我为什么在乎?好吧,我正在尝试使用咨询锁调试更大的问题,因此了解这一点可能有助于我理解这一点)

const models = require('../models')();
const factory = require('./factory')();

const LOCK_CODE = 2;

describe('advisory lock', function testLock() {
    this.timeout(5000);
    let organisation;
    let person;

    function delay(t, v) {
        return new Promise(function(resolve) {
            setTimeout(resolve.bind(null, v), t)
        });
    }

    before(async () => {
        // Comment these 2 lines and everything works!?!
        await cleanDb();
        await delay(2000);

        organisation = await factory.create('organisation');
        person = await factory.create('person');
    });
    after(() => cleanDb());

    describe.only('in session', () => {
        it('does not block', () => {
            const promises = [];
            for (let i = 0; i < 3; i++) {
                promises.push(sessionLock(organisation, person, i));
            }

            return Promise.all(promises);
        });
    });
});

async function sessionLock(organisation, person, id) {
    console.log(`${id} starting`);
    await models.Organisation.sequelize.query(`SELECT pg_advisory_lock(${LOCK_CODE}) FROM organisations WHERE id = ${organisation.id}`);

    console.log(`${id} got lock`);

    await models.Person.findAll({ where: { id: person.id } });

    await models.Organisation.sequelize.query(`SELECT pg_advisory_unlock(${LOCK_CODE}) FROM organisations WHERE id = ${organisation.id}`);
    console.log(`${id} finished`);
}

0 个答案:

没有答案