Node.js连接池在错误

时间:2017-01-27 19:56:19

标签: javascript node.js promise connection-pooling node-mysql

我最近将我的通用池包升级到版本3,它使用了承诺 - 这个概念我可能不太了解。尽管在操作上有一些意想不到的差异,但我已设法使其正常工作。

我遇到的问题是我开始测试错误情况。我故意将密码设置错误,并且在测试时,我得到一个无限循环的"连接失败"错误 - 表示尽管出现错误,仍会触发创建函数。我假设我已经错误地配置了池,或者我收集不正确。

通用池工厂:

const poolFactory = {
  create: function() {
    return new Promise(function(resolve, reject) {
      var client = mysql.createConnection({
        host: config.host,
        user: config.user,
        password: config.pass,
      });
      client.connect(function(err) {
        if (err != null) {
          log.write('ERROR', "Connection Error: MySQL: " + err.message);
          reject(err);
        } else {
          log.write('INFO', "MySQL Connection created.");
          resolve(client);
        }
      });

    })
  },
  destroy: function(client) {
    return new Promise(function(resolve) {
      client.end(function(err) {
        if (err != null) {
          log.write('ERROR', "DB Error: MySQL: " + err.message);
        } else {
          log.write('INFO', "Database connection closed.");
          resolve();
        }
      });
    })
  }
}

const cp = genericPool.createPool(poolFactory);

触发连接错误的测试查询:

cp.acquire().then(
  function(client) {
    client.query('USE ' + config.db, function(err, results, fields) {
      if (err != null) {
        log.write('ERROR', "DB test error: MySQL: " + err.message);
      } else {
        log.write('INFO', "MySQL connection tested successfully.");
        cp.release(client)
      }
    });
  }).catch(function(err) {
  cp.release(client);
  log.write('ERROR', "Pool Error: " + err.message);
});

我的错误日志填满了一百万行:

 Connection Error: MySQL: ER_ACCESS_DENIED_ERROR: Access denied for user 'user'@'localhost' (using password: YES)

我期待一个错误,因为我正在测试错误条件。得到无限循环我做错了什么?我认为拒绝(错误)应该将承诺置于一个不再回答任何问题的状态?

有人能指出我正确的方向吗?

一如既往 - 非常感谢你!

编辑:这是一个完整的脚本,可以说明问题,如果有人关心第一手问题!控制台填满" ERROR MySQL连接错误:ER_ACCESS_DENIED_ERROR:拒绝访问用户' devUser' @' localhost' (使用密码:是)"。再次感谢。

// Test App to show logging issue

var pool = require('generic-pool'),
  mysql = require('mysql')

var config = {
  port: 8880,
  host: 'localhost',
  user: 'devUser',
  pass: 'wrong-pass',
  db: 'node-app-db'
}

const poolConfig = {
  max: 3
};

const poolFactory = {
  create: function() {
    return new Promise(function(resolve, reject) {
      var client = mysql.createConnection({
        host: config.host,
        user: config.user,
        password: config.pass,
      });
      client.connect(function(err) {
        if (err != null) {
          console.log('ERROR', "MySQL Connection Error: " + err.message);
          reject(err);
        } else {
          console.log('USAGE', "MySQL Connection created. " + cp.size + " of " + config.poolSize + " connections to DB in use.");
          resolve(client);
        }
      });

    })
  },
  destroy: function(client) {
    return new Promise(function(resolve) {
      client.end(function(err) {
        if (err != null) {
          console.log('ERROR', "DB Error: MySQL: " + err.message);
        } else {
          console.log('USAGE', "Database connection closed. Pool contains ' + cp.size + ' more connections.");
          resolve();
        }
      });
    })
  }
}

const cp = pool.createPool(poolFactory, poolConfig);

cp.acquire().then(
  function(client) {
    client.query('USE ' + config.db, function(err, results, fields) {
      if (err != null) {
        console.log('ERROR', "DB test error: MySQL: " + err.message);
      } else {
        console.log('READY', "MySQL connection tested successfully. DataServer ready for connections.");
        cp.release(client)
      }
    });
  }).catch(function(err) {
  cp.release(client);
  console.log('ERROR', "Pool Error: " + err.message);
});

1 个答案:

答案 0 :(得分:0)

在github问题上从我原来的回复中交叉发布

嘿@whiteatom - 是的,你已经打到了“已知问题”的土地......

对于某些历史...... 在v2中,对pool.acquire的特定调用与factory.create的单个调用直接相关,而factory.create中的错误将导致pool.acquire。 (这通常是坏的️) 在v3中,对pool.acquire的调用与factory.create的调用没有任何关系,因此factory.create中的任何错误都无法冒充pool.acquire次调用,因为它没有任何语义感。相反,factory错误现在通过event emitters

通过Pool本身公开

总而言之:promise返回的pool.acquire只会因与acquire调用特别相关的错误(例如超时)而拒绝,而不是因为任何其他错误池中的错误。要捕获池中的常规错误,您需要将一些事件侦听器附加到您拥有的Pool实例。

如果你的factory.create返回只能拒绝的承诺,那么仍然存在这样的问题:池可能会以某种无限循环结束。为了解决这个问题,你可以在你的factory.create函数中构建退避功能(虽然这有点像黑客,但我真的需要找到一些方法来退回池本身。)