【问题标题】:Node MySQL Connection Pool - wait for database to start节点 MySQL 连接池 - 等待数据库启动
【发布时间】:2020-01-15 20:35:48
【问题描述】:

如何检查 MySQL 数据库是否已准备好接受来自 Node MySQL 连接池的某些查询?

我有一个由容器组成的 Docker 环境:

  • 容器 1:网络服务器
  • 容器 2:api
  • 容器 3:数据库

数据库容器运行 MySQL 数据库。 api 容器连接到该数据库。所有三个容器同时启动。 Web 服务器容器在 0.5 秒后启动。 api 容器在 2 秒后启动。数据库服务器在 20 秒后启动。

目前,api 会在数据库启动并运行之前尝试访问数据库的表。这会导致 connection denied 之类的错误。以下代码段总是以消息“查询数据库时出错!”结尾。当 MySQL 数据库尚未启动时:

const sql: string = 'SELECT * FROM sometable;';
MySQL.createPool({
    connectionLimit: 10,
    acquireTimeout: 30000,
    waitForConnections: true,
    database: 'mydatabase',
    host: 'localhost',
    multipleStatements: true,
    password: 'mypassword',
    user: 'root',
}).query(sql, (err, result) => {
    if (result) {
        console.log('Successfully queried database.');
    } else {
        console.log('Error querying database!');
    }
});

正在使用的版本:

OS: Ubuntu 19.10
Node: v13.6.0
MySQL (Node API): "@types/mysql": "2.15.8" and "mysql": "2.17.1"
MySQL (Docker Database): mysql:5.7.28
TypeScript: 3.7.4

我想通过 api 检查(并等待)数据库准备情况,可能使用我用于查询的连接池。这可能吗?

【问题讨论】:

    标签: mysql node.js connection-pooling


    【解决方案1】:

    重试连接setTimeout():

    (用Javascript而不是打字稿回答)

    'use strict';
    
    const dbpool = require('mysql').createPool({
        connectionLimit: 10,
        acquireTimeout: 30000,
        waitForConnections: true,
        database: 'mydatabase',
        host: 'localhost',
        multipleStatements: true,
        password: 'mypassword',
        user: 'root',
    });
    
    const sql = 'SELECT * FROM sometable;';
    
    const attemptConnection = () =>
      dbpool.getConnection((err, connection) => {
      if (err) {
        console.log('error connecting. retrying in 1 sec');
        setTimeout(attemptConnection, 1000);
      } else {
        connection.query(sql, (errQuery, results) => {
          connection.release();
          if (errQuery) {
            console.log('Error querying database!');
          } else {
            console.log('Successfully queried database.');
          }
        });
      }
    });
    
    attemptConnection();
    

    这是我的测试运行:

    $ sudo service mysql stop; node test.js & sudo service mysql start
    [1] 24737
    error connecting. retrying in 1 sec
    error connecting. retrying in 1 sec
    $ Successfully queried database.
    

    仅供参考,该程序永远不会结束,因为它需要dbpool.end()

    【讨论】:

    • IMO 在投反对票时必须提供声明。 @StackOverflow:请这样做! ;) 至于你的代码,它有帮助!它实际上是如此简单!谢谢你的帮助。
    • 你为什么不简单地用})());完成函数attemptConnection,即你自己调用它:blog.mgechev.com/2012/08/29/…
    • 我知道了,setTimeout 中的回调不能是自调用函数,因此忽略我最后的评论
    • @JoãoPimentelFerreira 你可以使用let attemptConnection; (attemptConnection = () => '...')(),但你不能使用const
    【解决方案2】:

    您的 API 应尝试在超时和一定的连接尝试阈值的情况下连接到数据库。但是,对于这种情况,有现成的解决方案。

    尝试使用wait-for-mysql 模块。

    waitForMy = require 'wait-for-mysql'
    config =
      username: user
      password: pass
      quiet: true
      query: 'SELECT 1'
    
    waitForMy.wait(config)
    

    【讨论】:

    • 您在wait-form-mysql 链接中有错字。它应该是wait-for-mysql。如果您查看它的源代码,它会执行我的建议,就在这里:setTimeout testConnection, connectDelay
    • @niry 我们应该始终使用现有的库,而不是重新发明轮子。感谢您的错字提示。
    • 您是否一路“重新发明轮子”?它只是 setTimeout() 并包装在一个函数中。
    • 我不反对使用库,您的解决方案可能工作得很好。以下是不使用库的示例原因:#1。你想学习。 #2。未维护的库往往会导致问题(仅供参考,最新提交时间为 2015 年 9 月 29 日)#3。在解决方案如此简单的情况下添加库并不能真正节省任何东西,事实上,它可能会花费您更多。
    • #1 - “成立于 2008 年,Stack Overflow 是最大、最受信任的在线社区,任何人都可以通过代码学习...”。 #3 - 每周下载量与是否节省时间之间绝对没有相关性。
    【解决方案3】:

    这里有一个变体,但不需要 mysql 池。我在我的服务器上使用它并且它确实有效:

    const mysql = require('mysql')
    var db // global, to use later to db.query
    var dbInfo = {
      host     : 'example.org',
      database : 'some_database',
      user     : 'bob',
      password : 'secret'
    }
    
    function connectToDb(callback) {
      const attemptConnection = () => {
        console.log('Attempting to connect to db')
        dbInfo.connectTimeout = 2000 // same as setTimeout to avoid server overload 
        db = mysql.createConnection(dbInfo)
        db.connect(function (err) {
          if (err) {
            console.log('Error connecting to database, try again in 1 sec...')
            db.destroy() // end immediately failed connection before creating new one
            setTimeout(attemptConnection, 2000)
          } else {
            callback()
          }
        })
      }
      attemptConnection()
    }
    
    // now you simply call it with normal callback
    connectToDb( () => {
      console.log('Connection successfully')
      // do some queries
      db.query(..)
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-06
      • 1970-01-01
      • 1970-01-01
      • 2018-03-14
      • 2018-09-30
      • 2012-08-03
      • 1970-01-01
      • 2019-11-15
      相关资源
      最近更新 更多