我有一个类似于以下项目。
dbClient.js
const dbClient = require('knex')({
client: 'pg',
connection: {
host: '127.0.0.1',
user: 'user',
password: 'password',
database: 'staging',
port: '5431'
}
})
module.exports = dbClient
libs.js
const knex = require('./dbClient.js')
async function doThis(email) {
const last = await knex('users').where({email}).first('last_name').then(res => res.last_name)
// knex.destroy()
return last
}
async function doThat(email) {
const first = await knex('users').where({email}).first('first_name').then(res => res.first_name)
// knex.destroy()
return first
}
module.exports = {
doThat,
doThis
}
test01.js
const {doThis, doThat} = require('./libs.js');
(async () => {
try {
const res1 = await doThis('user53@gmail.com')
console.log(res1)
const res2 = await doThat('user53@gmail.com')
console.log(res2)
} catch (err) {
console.log(err)
}
})()
如上所示,从knex.destroy()
中删除了libs.js
时。 node test01
可以输出res1
和res2
。但是问题是连接无限期地挂起,而CMD永不返回。
但是,如果我取消对knex.destroy()
中的libs.js
的注释,则doThis
将执行,CMD将挂在doThat
,因为在{{1 }}。
我的问题是:
doThis
的最佳位置是什么?还是有其他方法可以做到?
感谢您的时间!
答案 0 :(得分:2)
Knex destroy()似乎是一次性操作。销毁连接后,可能需要一个全新的连接池才能进行下一步操作。
您导出的db客户端模块被缓存到节点模块缓存中,并且不会在每次需要时创建新的连接池。
这是预期用途,应在应用程序退出或完成所有测试后销毁该池。如果您有理由为每个操作创建/销毁连接(例如在无服务器环境中),则不应重用已销毁的客户端,而应每次都创建一个新实例。
否则,它违反了连接池的目的。
答案 1 :(得分:0)
您可能通常不需要显式调用knex.destroy()
–这是文档本身所暗示的(强调我的意思):
如果您需要显式拆除连接池,则可以使用
knex.destroy([callback])
。
答案 2 :(得分:0)
在每次查询后销毁连接就像每次弹音符时都把吉他收拾起来。只需在演出开始时将其拔出,播放所有歌曲,然后将其收起即可。
同样,对于应用程序的其余部分,请在完成连接后销毁连接,而不是在每次查询后都销毁。在Web服务器中,这可能永远不会发生,因为您将在不确定的时间点用信号杀死它,并且直到那时该应用程序都可能需要有效的连接。
对于测试,您可能需要使用destroy
函数来避免挂起。同样,在如上所示的(人为?)应用程序中,如果遇到挂起并且该应用程序被卡住,请在完成连接后销毁该连接一次。
这是Mocha的一个说明性示例,它在评论中被提及,这似乎是一个相当合理的假设,即该主题(或类似内容)正在被结识该主题的人们使用。在所有测试之前进行设置,在所有测试之后进行拆卸以及按测试进行案例设置和拆卸的模式是通用的。
与您的问题有关,after(() => knex.destroy());
是所有测试结束时的拆除电话。没有这个,摩卡就会死机。请注意,我们还关闭了每个测试的http服务器,因此有多个候选对象可以挂起测试套件以进行查找。
server.js
:const express = require("express");
const createServer = (knex, port=3000) => {
const app = express();
app.get("/users/:username", (request, response) => {
knex
.where("username", request.params.username)
.select()
.first()
.table("users")
.then(user => user ? response.json({data: user})
: response.sendStatus(404))
.catch(err => response.sendStatus(500))
});
const server = app.listen(port, () =>
console.log(`[server] listening on port ${port}`)
);
return {
app,
close: cb => server.close(() => {
console.log("[server] closed");
cb && cb();
})
};
};
module.exports = {createServer};
server.test.js
:const chai = require("chai");
const chaiHttp = require("chai-http");
const {createServer} = require("./server");
const {expect} = chai;
chai.use(chaiHttp);
chai.config.truncateThreshold = 0;
describe("server", function () {
this.timeout(3000);
let knex;
let server;
let app;
before(() => {
knex = require("knex")({
client: "pg",
connection: "postgresql://postgres@localhost",
});
});
beforeEach(done => {
server = createServer(knex);
app = server.app;
knex
.schema
.dropTableIfExists("users")
.then(() =>
knex.schema.createTable("users", table => {
table.increments();
table.string("username");
})
)
.then(() => knex("users").insert({
username: "foo"
}))
.then(() => done())
.catch(err => done(err));
});
afterEach(done => server.close(done));
after(() => knex.destroy());
it("should get user 'foo'", done => {
chai
.request(app)
.get("/users/foo")
.then(response => {
expect(response.status).to.equal(200);
expect(response).to.be.json;
expect(response.body).to.be.instanceOf(Object);
expect(response.body.data).to.be.instanceOf(Object);
expect(response.body.data.username).to.eq("foo");
done();
})
.catch(err => done(err));
});
});
"knex": "0.21.6",
"express": "4.17.1",
"mocha": "8.0.1",
"pg": "8.3.0",
"node": "12.19.0"