Node.js MySQL обработка ошибок в обещании

0

Я использую node.js и express, также mysql. Я использую пул соединений для запроса соединений и создания обещания на нем, чтобы ограничить кошмар обратного вызова, следующий фрагмент установлен в файле, который я импортирую позже, обратите внимание, что я установил обработчик при error чтобы не разорвать приложение в случае что-то действительно не так

exports.getConnection = () => {
    return new Promise((resolve, reject) => {
        pool.getConnection((err, connection) => {
            if (err) {
                reject('Could not obtain the connection from the pool: ${err}');
            }
            connection.on('error', err => {
                console.log('SQL error (code: ${err.code}, message: ${err.sqlMessage}) while executing query: ${err.sql}');
            });
            resolve(connection);
        });
    });
};

И вот пример usecase (идея состоит в том, чтобы получить соединение, связать запрос в then, и если произойдет не фатальная ошибка, я брошу его и обработаю выпуск соединения в обработчике catch

// Exception handler that release the connection then call the callback
function releaseConnectionHandler(err, connection, callback) {
    connection.release();
    callback(err, null);
}
exports.someRequest = function(ID, callback) {
    sqlPool.getConnection().then(connection => {
        connection.query("SELECT * from tableNotExists",
                        (err, result) => {
            if (err) { 
                throw ({ err, connection, callback }); 
            }
            connection.release();
            callback(null, result);
            });
    }).catch(({ err, connection, callback}) => releaseConnectionHandler(err, connection, callback));
};

Запрос не удастся, но я вижу, что обработчик даже не вызван (я вложил в него некоторый след...), и приложение завершается

node_modules/mysql/lib/protocol/Parser.js:80
        throw err; // Rethrow non-MySQL errors

Правильное querie yoeld никаких проблем... Любые идеи, что я сделал неправильно при обработке ошибок?

  • 0
    Вместо того, чтобы выдавать ошибку, вы должны отказаться от обещания. Кроме того, ваш код выше смешивает одинарные и двойные кавычки в вашем запросе.
Теги:
express

1 ответ

2
Лучший ответ

Вы повторно бросаете ошибку, переданную на обратный вызов вашего запроса, которую библиотека, которую вы используете, затем повторно бросает, а также, наконец, неправильно попадает и обрабатывается в любом месте и приводит к ошибке. Вы не находитесь в контексте обещания при throw, а в контексте функции обратного вызова, вызванной из модуля mysql.

Вы также излишне смешиваете обещания и обратные вызовы, в частности функцию, которую вы экспортируете. Ваш вопрос указывает, что вы хотите отойти от обратных вызовов, поэтому я собираюсь основать этот ответ на этом показании.

Чтобы решить основную проблему, не бросайте ошибку. Вместо этого передайте его вызывающему:

const promisify = require("util").promisify;

exports.someRequest = function (ID) {
  return sqlPool.getConnection().then(connection => {
    return promisify(connection.query)("select * from tableNotExist")
      .finally(connection.release);
  });
};

Соединение всегда будет возвращено в пул, будь то успешное или с ошибкой. Затем вы можете вызвать метод с помощью:

yourModule.someRequest(id).then((results) => {
  // Do something with the result set
}).catch((e) => {
  // Handle error. Can be either a pool connection error or a query error.
});

Если у вас есть возможность использовать async/await, код можно переписать:

const promisify = require("util").promisify;

exports.someRequest = async function (ID) {
  let connection = await sqlPool.getConnection();
  try {
    return await promisify(connection.query)("select * from tableNotExist");
  } finally {
    connection.release();
  }
};

Я также рекомендую использовать node-mysql2 поскольку у них есть API-интерфейс на основе Promise в дополнение к API-интерфейсу обратного вызова и, как мне кажется, улучшает производительность. Тогда вам не нужно писать эти утомительные обертки и вместо этого просто require('mysql2/promise') и быть хорошим.

  • 0
    В качестве дополнительного вопроса, почему обещание возврата все еще помнит включающий блок try{...} finally {...} ? Исходя из C ++, это кажется очень странным, я не думаю, что это имеет какое-либо отношение к замыканию, так как AFAIK имеет дело с включением переменных, а не спецификаторов try-catch-finally?
  • 0
    @zebullon Извинения, я пропустил добавление await прежде чем вернуть его. Предыдущее решение имело ошибку, которая высвобождала соединение обратно в пул до завершения запроса. Теперь, когда есть выражение await , оно сначала будет ждать завершения запроса, прежде чем выполнить ключ finally -block (и вернуть значение). Имеет ли это смысл?
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню