关于 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秒检查一次

解释

  1. 创建连接池:我们使用 generic-pool 创建一个连接池,用于管理 MongoDB 连接。
  2. 定义 removeNotWritable 函数:这个函数会遍历连接池中的所有可用连接,检查它们是否可读可写。如果连接不可写,则调用 destroy 方法销毁该连接。
  3. 修改 dispense 函数:在 dispense 函数中调用 removeNotWritable 函数,确保在获取连接之前移除失效的连接。
  4. 定时检查:你可以定期调用 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 可能需要根据实际情况调整。

回到顶部