关于 Nodejs 中使用 generic-pool 连接mongodb的一个问题
关于 Nodejs 中使用 generic-pool 连接mongodb的一个问题
我从网上看到的(我用这个连接mongodb,发现不太好用,你们有遇到么?):
generc-pool小巧精悍,总共只有几百行,完全由js代码写成。使用的方法页很简单。但是有一点不足的地方是,实例A和实例B建立链接,初始化连接池poolAB之后,如果实例A在守护进程的作用下进行了重启,此时poolAB中的所有连接都会失效,但是generic-pool本身只对超时的连接进行了处理,对于这种虽然没有超时但是已经失效的连接并没有相应操作。这个缺陷为我的工作带来了极大困扰。我对该模块进行了小小的改动,实现了对失效链接的处理。
其实就添加了一个函数:
function removeNotWritable() {
var toKeep = [],
i,
al;
// Go through the available (idle) items,
// check if they are not writeable
for (i = 0, al = availableObjects.length; i < al; i += 1) {
if (availableObjects[i]["obj"]["writable"] != false && availableObjects[i]["obj"]["readable"] != false ) {
// Client is writeable, so keep it.
toKeep.push(availableObjects[i]);
} else {
// The client is not writeable, call it's destroyer.
// log("removeIdle() destroying obj - now:" + now + "not writeable");
me.destroy(availableObjects[i].obj);
}
}
// Replace the available items with the ones to keep.
availableObjects = toKeep;
al = availableObjects.le`n`gth;
}
这个函数遍历了连接池中所有现存的连接句柄,判断是否可读可写,若不可以,则证明该连接失效,删除此连接。在dispense()函数的如下位置调用该函数即可实现对失效连接的销毁。
function dispense() {
......
if (waitingCount > 0) {
removeNotWritable();
if (availableObjects.length > 0) { .....................
2 回复
关于 Nodejs 中使用 generic-pool 连接 MongoDB 的一个问题
在使用 Node.js 和 generic-pool
库来管理 MongoDB 连接池时,可能会遇到一些挑战。特别是当你的应用在某个实例上重启时,之前建立的连接可能会失效,但 generic-pool
并不会自动处理这些失效的连接。
示例代码
假设你有一个简单的 Node.js 应用程序,使用 generic-pool
来管理 MongoDB 连接池,并且你希望在连接失效时能够自动销毁这些连接。
const genericPool = require('generic-pool');
const MongoClient = require('mongodb').MongoClient;
// 创建一个连接池
const pool = genericPool.createPool({
create: async () => {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true, useUnifiedTopology: true });
return client.db('testdb');
},
destroy: async (client) => {
await client.close();
},
max: 5,
min: 0,
idleTimeoutMillis: 30000,
acquireTimeoutMillis: 30000
}, {
// 配置项
});
// 添加一个函数来移除不可写的连接
async function removeNotWritable() {
const toKeep = [];
for (let i = 0; i < pool._availableObjects.length; i++) {
const client = pool._availableObjects[i];
if (client.writable && client.readable) {
// 客户端可读可写,保留它
toKeep.push(client);
} else {
// 客户端不可写,销毁它
await pool.destroy(client);
}
}
// 替换可用对象列表
pool._availableObjects = toKeep;
}
// 修改 dispense 函数以调用 removeNotWritable
pool.acquire().then(client => {
// 使用 client 进行数据库操作
// ...
// 释放客户端
pool.release(client);
}).catch(err => {
console.error('Error acquiring client:', err);
});
// 在需要的时候调用 removeNotWritable
setTimeout(() => {
removeNotWritable();
}, 10000); // 每10秒检查一次
解释
- 创建连接池:我们使用
generic-pool
创建一个连接池,用于管理 MongoDB 连接。 - 定义
removeNotWritable
函数:这个函数会遍历连接池中的所有可用连接,检查它们是否可读可写。如果连接不可写,则调用destroy
方法销毁该连接。 - 修改
dispense
函数:在dispense
函数中调用removeNotWritable
函数,确保在获取连接之前移除失效的连接。 - 定时检查:你可以定期调用
removeNotWritable
函数,确保连接池中的连接始终有效。
通过这种方式,你可以有效地管理 MongoDB 连接池,避免由于连接失效导致的问题。
在Node.js中使用generic-pool
连接MongoDB时,确实会遇到连接失效的问题。你的描述表明,当实例进行重启后,之前的连接池中的连接会失效。generic-pool
默认只会处理超时的连接,而不会处理这些虽然没有超时但已失效的连接。
为了处理这种情况,你可以按照你的描述,在dispense
方法中调用一个函数来检查并移除不可读写的连接。以下是一个完整的示例代码:
const genericPool = require('generic-pool');
const MongoClient = require('mongodb').MongoClient;
// 创建连接池配置
const poolConfig = {
max: 5, // 最大连接数
min: 1, // 最小连接数
idleTimeoutMillis: 30000, // 空闲超时时间
};
// 创建连接池
const pool = new genericPool.Pool({
create: async () => {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true, useUnifiedTopology: true });
return client.db('testdb');
},
destroy: async (client) => {
await client.close();
},
}, poolConfig);
async function removeNotWritable() {
const availableObjects = pool._allObjects;
let toKeep = [];
for (let obj of availableObjects) {
if (obj.obj && obj.obj.client && obj.obj.client.topology && obj.obj.client.topology.isConnected()) {
toKeep.push(obj);
} else {
pool.destroy(obj.obj);
}
}
// 替换可用对象
pool._allObjects = toKeep;
}
async function dispense() {
removeNotWritable(); // 在获取连接前先检查并移除失效连接
try {
const resource = await pool.acquire();
console.log('Got resource:', resource);
// 使用资源...
await pool.release(resource);
} catch (err) {
console.error('Error acquiring resource:', err);
}
}
dispense().catch(console.error);
解释
removeNotWritable
函数遍历连接池中的所有连接,检查它们是否仍然有效。- 如果连接失效(例如,由于实例重启),则通过调用
pool.destroy(obj.obj)
将其关闭。 dispense
方法在尝试获取连接之前调用removeNotWritable
,以确保获取到的连接是有效的。
请注意,generic-pool
的内部实现可能会发生变化,因此直接访问 _allObjects
可能需要根据实际情况调整。