Как решить nodejs uncaughtException: ошибка подключения уже выпущена и MaxListenersExceededWarning? - PullRequest
4 голосов
/ 15 марта 2020

Я создаю express сервер для получения запроса (диктовку из 10 элементов) от моего переднего плана реакции и затем сохраняю данные в базе данных. Ниже мой код. Я обнаружил, что мой код работает, и запрос сохраняет запись обратно в Db. Но в каждом для l oop эта ошибка возвращается на сервере. Какова причина этой ошибки и MaxListenersExceededWarning?

The request data: 
{{.....}, {.....}, {.....}, {.....}, {.....}} #10 item

Code:
connection.js:
const p = mysql.createPool({
  "connectionLimit" : 100,
  "host": "example.org",
  "user": "test",
  "password": "test",
  "database": "test",
  "multipleStatements": true
});

const getConnection = function(callback) {
    p.getConnection(function(err, connection) {
        callback(err, connection)
    })
};

module.exports = getConnection

routers.js
router.post('/test', (req, res) => {
    getConnection(function(err, conn){
        if (err) {
            return res.json({ success: false, error: err })
        } else {
          const dict = req.body;
          Object.keys(dict).forEach(function(r){
              #putting dict's value to query 
              query = "UPDATE ......;"
              conn.query(query, function (err, result, fields) {
                conn.release()
                console.log(query)
                  if (err) {
                      console.log("err")
                      return res.json({ success: false, error: err });
                  }
              });
            });
          }
        });
        return res.json({ success: true });
    });

Error:
error: uncaughtException: Connection already released
Error: Connection already released
    at Pool.releaseConnection (/home/node_modules/mysql/lib/Pool.js:138:13)
    at PoolConnection.release (/home/node_modules/mysql/lib/PoolConnection.js:35:15)
    at Query.<anonymous> (/home/routes/test.js:276:22)
    at Query.<anonymous> (/home/node_modules/mysql/lib/Connection.js:526:10)
    at Query._callback (/home/node_modules/mysql/lib/Connection.js:488:16)
    at Query.Sequence.end (/home/node_modules/mysql/lib/protocol/sequences/Sequence.js:83:24)
    at Query._handleFinalResultPacket (/home//node_modules/mysql/lib/protocol/sequences/Query.js:149:8)
    at Query.OkPacket (/home//node_modules/mysql/lib/protocol/sequences/Query.js:74:10)
    at Protocol._parsePacket (/home//node_modules/mysql/lib/protocol/Protocol.js:291:23)
    at Parser._parsePacket (/home//node_modules/mysql/lib/protocol/Parser.js:433:10)
(node:15881) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 finish listeners added. Use emitter.setMaxListeners() to increase limit

1 Ответ

4 голосов
/ 15 марта 2020

Одно соединение (conn) извлекается из пула и используется для запуска 10 запросов в forEach l oop.

Когда первый запрос завершается, первый шаг его обратного вызова: conn.release(). Соединение освобождается.

Когда второй запрос завершается, его обратный вызов также пытается освободить соединение, вызывая ошибку.

Эта проблема может быть решена несколькими способами:

Решить с помощью счетчика

В обратном вызове запроса к базе данных перед вызовом call.release проверьте количество уже обработанных запросов и закройте соединение только при обработке последнего продукта.

      const dict = req.body;

      // initialize counter
      let itemCount = 0
          , errors = []

      Object.keys(dict).forEach(function(r){
          #putting dict's value to query 
          query = "UPDATE ......;"
          conn.query(query, function (err, result, fields) {


            // check whether this is the last callback
            if (itemCount === dict.length-1) {
                conn.release()

                let result = errors.length ? { success: false, error: errors } : { success: true }

                res.json(result)

            }

            // increment counter
            itemCount++

            console.log(query)
              if (err) {
                  console.log("err")
                  errors.push(err)
              }
          });
        });

Редактировать : Существует также проблема с вызовами res.json: внутри кода в вопросе, res.json({ success: true }) всегда выполняется без ожидания результатов выполнения запросов. В приведенном выше примере измененного кода вызывается res.json только один раз после выполнения всех запросов, это единственное место, где следует вызывать res.json. Это подразумевает изменение кода на стороне клиента, чтобы он мог обрабатывать массив ошибок, а не только одну ошибку.

Решить с помощью рекурсивной функции вместо l oop.

Не рекомендуется использовать циклы for для выполнения асинхронного кода. Вы можете столкнуться с ошибками Maximum call stack size exceeded всякий раз, когда объем данных становится слишком большим.

Вместо этого создайте рекурсивную функцию (например, updateDictItem) для обработки одного запроса на обновление за раз. Подробнее об асинхронных шаблонах см. В node.js в этой статье .

Другие возможные улучшения

Вместо того, чтобы запускать десять запросов к базе данных, стоит рассмотреть возможность группировки всех обновлений. в одном MERGE операторе обновления , в противном случае выполняются все обновления в TRANSACTION.

...