【问题标题】:How can I find which MySQL query is causing errors in my NodeJS app?如何在我的 NodeJS 应用程序中找到导致错误的 MySQL 查询?
【发布时间】:2017-01-30 21:27:00
【问题描述】:

我在 NodeJS 和 HapiJS 之上构建了一个 api。

应用程序在启动时会加载大量数据,然后将其保存在内存中。我有这个应用程序在具有 16 GB RAM 的服务器上运行,因此应该可以在内存中保存 4 GB RAM。

但是,每次应用启动时,日志中都会出现 5 次此错误:

{ Error: connect ETIMEDOUT
    at Connection._handleConnectTimeout (/home/ec2-user/daemons/liar_lies/node_modules/mysql/lib/Connection.js:425:13)
    at Socket.g (events.js:291:16)
    at emitNone (events.js:86:13)
    at Socket.emit (events.js:185:7)
    at Socket._onTimeout (net.js:339:8)
    at ontimeout (timers.js:365:14)
    at tryOnTimeout (timers.js:237:5)
    at Timer.listOnTimeout (timers.js:207:5)
    --------------------
    at Protocol._enqueue (/home/ec2-user/daemons/liar_lies/node_modules/mysql/lib/protocol/Protocol.js:141:48)
    at Protocol.handshake (/home/ec2-user/daemons/liar_lies/node_modules/mysql/lib/protocol/Protocol.js:52:41)
    at Connection.connect (/home/ec2-user/daemons/liar_lies/node_modules/mysql/lib/Connection.js:136:18)
    at /home/ec2-user/daemons/liar_lies/node_modules/knex/lib/dialects/mysql/index.js:106:18
    at Promise._execute (/home/ec2-user/daemons/liar_lies/node_modules/bluebird/js/release/debuggability.js:300:9)
    at Promise._resolveFromExecutor (/home/ec2-user/daemons/liar_lies/node_modules/bluebird/js/release/promise.js:481:18)
    at new Promise (/home/ec2-user/daemons/liar_lies/node_modules/bluebird/js/release/promise.js:77:14)
    at Client_MySQL.acquireRawConnection (/home/ec2-user/daemons/liar_lies/node_modules/knex/lib/dialects/mysql/index.js:104:12)
    at Object.create (/home/ec2-user/daemons/liar_lies/node_modules/knex/lib/client.js:231:16)
    at Pool._createResource (/home/ec2-user/daemons/liar_lies/node_modules/generic-pool/lib/generic-pool.js:326:17)
    at Pool.dispense [as _dispense] (/home/ec2-user/daemons/liar_lies/node_modules/generic-pool/lib/generic-pool.js:314:12)
    at Pool.acquire (/home/ec2-user/daemons/liar_lies/node_modules/generic-pool/lib/generic-pool.js:392:8)
    at /home/ec2-user/daemons/liar_lies/node_modules/knex/lib/client.js:281:19
    at Promise._execute (/home/ec2-user/daemons/liar_lies/node_modules/bluebird/js/release/debuggability.js:300:9)
    at Promise._resolveFromExecutor (/home/ec2-user/daemons/liar_lies/node_modules/bluebird/js/release/promise.js:481:18)
    at new Promise (/home/ec2-user/daemons/liar_lies/node_modules/bluebird/js/release/promise.js:77:14)
  errorno: 'ETIMEDOUT',
  code: 'ETIMEDOUT',
  syscall: 'connect',
  fatal: true }

这是唯一的错误,每次应用启动时都会发生 5 次。

然而,该应用程序似乎确实获得了我期望它获得的大部分数据,所以无论查询抛出此错误,它一定是相当模糊的。

如何确定哪个查询是引发此错误的查询?

堆栈跟踪似乎没有提到我的代码中导致此问题的行。 (我觉得这很令人沮丧。)

这些是我正在使用的模块:

"boom": "3.1.2",
"code": "2.1.0",
"fs": "0.0.2",
"glob": "6.0.4",
"glue": "3.1.0",
"good-console": "5.3.0",
"good-file": "5.1.2",
"hapi": "16.0.2",
"html-entities": "1.2.0",
"joi": "7.2.2",
"knex": "0.12.6",
"knex-logger": "0.1.0",
"multiline": "1.0.2",
"mysql": "2.12.0",
"path": "0.12.7",
"plugo": "0.3.1"

据我所知,只有 2 个函数在启动时调用数据库。这是其中之一:

function build_maps_which_index_database_data(query, which_type_of_data_in_which_database_table) {

    DB.knex.raw(query).then(
        function(result) {
        var count_of_database_results = result[0].length;
        build_list_of_allowed_fields(result[0][0]);

        for(var how_many_records_processed_so_far = 0; how_many_records_processed_so_far < count_of_database_results; how_many_records_processed_so_far++) {
            var document = result[0][how_many_records_processed_so_far];
            var profile_id = document['profile_id'];
            document['which_type_of_data_in_which_database_table'] = which_type_of_data_in_which_database_table;
            document['item_id'] =  uuidV4(); 

            build_map_of_uuid_ids_to_documents(document);   

            Object.keys(document).forEach(function(name_of_field_in_database) {
                // avoiding name_of_field_in_database = profile_id
                if (name_of_field_in_database != 'profile_id') {
                    var string_from_database = document[name_of_field_in_database];
                    build_map_of_santized_words_to_uuid_ids(name_of_field_in_database, string_from_database, document['item_id']);
                }
            });
        }
        })
    .catch(function(e) {
            console.log('Error:     calling code was get_map_of_santized_words_to_uuid_ids'); 
            console.log('query was: ' + query); 
        console.error(e);      
    });
}

这些函数中的每一个都附加了一个“catch”子句,所以我假设它是错误的原因,那么我会在日志中看到它。

【问题讨论】:

  • 使用Sequelize 可以让您更好地控制错误,而不是与低级 MySQL 驱动程序相撞。你可以catch他们并回溯到根本原因。
  • 显示你的初始化代码,我们猜不出来。
  • Paul,如果我不清楚,我很抱歉,但是任何引发错误的代码都是我不知道的代码。我编写的初始化代码运行正确,没有错误,并加载了我希望看到的加载数据。但是在日志中,每次启动应用程序时都会出现 5 个错误。我担心导致这些错误的原因。我正在努力追查他们。
  • Tadman,我们使用 knex,它的作用似乎与 Sequelize 相同。每个数据库调用都有一个附加的“catch”子句。我已经在上面发布了一个示例。

标签: mysql node.js hapijs knex.js


【解决方案1】:

问题中的错误不是由您在问题中包含的代码引起的。

要了解发送这些错误时发生的情况,请尝试使用环境变量 DEBUG=knex:* 运行应用程序。这将向您展示连接池中发生的情况以及发送到数据库的查询。

export DEBUG=knex:*
cd ~/yourapp
node server.js

或者只是

cd ~/yourapp
DEBUG=knex:* node server.js

还可以尝试从应用程序中删除代码,直到应用程序中的代码量最少,这仍然会产生这些错误。之后应该很容易找到问题的根本原因。

您可以做的另一件事是将调试信息添加到

knex.on('query-error', function (err, obj) { ... }); 

事件并检查是否捕获了这些错误。

【讨论】:

  • 嗯,我收到这个错误:DEBUG=knex:* ^ SyntaxError: Unexpected token :
  • @LRK9 必须设置为shell的环境变量。我会用一个例子来更新答案。
  • @LRK9 如果遇到该错误,您可以尝试将值括在引号中。例如:DEBUG="knex:*"
猜你喜欢
  • 2020-10-06
  • 2021-06-13
  • 2012-01-09
  • 1970-01-01
  • 2018-05-08
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 2015-07-10
相关资源
最近更新 更多