종료를 호출 한 후 핸드 셰이크를 대기열에 넣을 수 없습니다.


82

다음 코드를 구현했습니다.

module.exports = {
    getDataFromUserGps: function(callback)
    {
        connection.connect();
        connection.query("SELECT * FROM usergps", 
            function(err, results, fields) {
                if (err) return callback(err, null);
                return callback(null, results);
            }
        ); 
        connection.end();
    },
    loginUser: function(login, pass, callback)
    {
        connection.connect();
        connection.query(
            "SELECT id FROM users WHERE login = ? AND pass = ?",
            [login, pass],
            function(err, results, fields) 
            {
                if (err) return callback(err, null);
                return callback(null, results);
            }
        ); 
        connection.end();
    },
    getUserDetails: function(userid, callback)
    {
        connection.connect();
        connection.query(
            "SELECT * FROM userProfilDetails LEFT JOIN tags ON userProfilDetails.userId = tags.userId WHERE userProfilDetails.userid = ?",
            [userid],
            function(err, results, fields)
            {
                if (err) return callback(err, null);
                return callback(null, results);
            }
        );
        connection.end();
    },
    addTags: function(userId, tags)
    {
        connection.connect();
        connection.query(
            "INSERT INTO tag (userId, tag) VALUES (?, ?)",
            [userId, tags],
            function(err, results, fields)
            {
                if (err) throw err;
            }
        )
        connection.end();
    }
}

모든 것이 처음으로 만 잘 작동합니다. 두 번째로 쿼리를 "사용"하려면 다음 오류가 발생합니다.

Cannot enqueue Handshake after invoking quit

나는 .end()연결하지 않으려 고 노력했지만 도움이되지 않았습니다.

이 문제를 어떻게 해결할 수 있습니까?


2
질문을 닫아 주실 수 있나요?
Andrew Rhyne 2013-01-29

나를 위해 하나가 열려있는 동안 연결을 열려고 할 때 오류가 발생했습니다 (즉, 서로 옆에 두 개의 connection.connect () 호출이 있음)
sqram

호출 connection.end내측 connection.query비동기 적 실행되므로 콜백 함수.
Arjun Singh

답변:


241

node-mysql 모듈을 사용하는 경우 .connect 및 .end를 제거하십시오. 직접 문제를 해결했습니다. 분명히 그들은 버그가 발생한 마지막 반복에서 불필요한 코드를 밀어 넣었습니다. createConnection 호출을 이미 실행 한 경우에는 연결할 필요가 없습니다.


21
그것은 내가 찾은 최악의 대답입니다! 당신이 연결을 만들고, 지금, 열 때, 우리는 함수에 MySQL의 노드를 만들 생각 함수가 호출 때마다, 그것은 짧은 시간 후, 당신은 MySQL의 연결의 최대 한계 도달을 얻을 만들고 열려있는 연결을 유지
아타

4
그렇다면 당신은 그것을 잘못하고 있습니다. 당신은 연결을 다시 해야하는
앤드류 Rhyne을

6
@ata node-mysql은 연결 풀을 구현합니다. 실제 요청이 아니기 때문에 모든 요청에서 연결 개체를 파괴해서는 안됩니다. 귀하의 댓글이 찬성 투표를받는 이유도 확실하지 않습니다. 분명히 사람들은 문서를 읽고되지 않습니다
앤드류 Rhyne

5
aws lambda에서 실행중인 경우 연결을 닫지 않으면 lambda가 계속 시간 초과됩니다. 따라서 이러한 모든 제안은 도움이되지 않습니다. 이 문제에 대해 며칠을 보냈습니다.
Joseph Bolade Caxton-Idowu

나를 위해 작동하는 감사합니다. @ XP1의 아래 답변은이 동작에 대한 자세한 내용을 제공합니다.
KeitelDOG

54

에 따르면 :

TL; DR 연결이 createConnection끊길 때마다 메서드 를 호출하여 새 연결을 설정해야합니다 .

참고 : 웹 요청을 제공하는 경우 모든 요청에서 연결을 종료해서는 안됩니다. 서버 시작시 연결을 만들고 연결 / 클라이언트 개체를 사용하여 항상 쿼리하십시오. 오류 이벤트를 수신하여 서버 연결 해제를 처리하고 다시 연결할 수 있습니다. 여기에 전체 코드가 있습니다 .


에서:

그것은 말한다 :

서버 연결 해제

네트워크 문제, 서버 시간 초과 또는 서버 충돌로 인해 MySQL 서버와의 연결이 끊어 질 수 있습니다. 이러한 모든 이벤트는 치명적인 오류로 간주되며 err.code = 'PROTOCOL_CONNECTION_LOST'. 자세한 내용은 오류 처리 섹션을 참조하십시오.

이러한 예기치 않은 연결 해제를 처리하는 가장 좋은 방법은 다음과 같습니다.

function handleDisconnect(connection) {
  connection.on('error', function(err) {
    if (!err.fatal) {
      return;
    }

    if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
      throw err;
    }

    console.log('Re-connecting lost connection: ' + err.stack);

    connection = mysql.createConnection(connection.config);
    handleDisconnect(connection);
    connection.connect();
  });
}

handleDisconnect(connection);

위의 예에서 볼 수 있듯이 새 연결을 설정하여 연결을 다시 연결합니다. 일단 종료되면 기존 연결 개체는 설계 상 다시 연결할 수 없습니다.

풀을 사용하면 연결이 끊긴 연결이 풀에서 제거되어 다음 getConnection 호출에서 새 연결이 생성 될 공간을 확보합니다.


연결이 필요할 때마다 이니셜 라이저 함수가 핸들러를 자동으로 추가하도록 함수를 조정했습니다.

function initializeConnection(config) {
    function addDisconnectHandler(connection) {
        connection.on("error", function (error) {
            if (error instanceof Error) {
                if (error.code === "PROTOCOL_CONNECTION_LOST") {
                    console.error(error.stack);
                    console.log("Lost connection. Reconnecting...");

                    initializeConnection(connection.config);
                } else if (error.fatal) {
                    throw error;
                }
            }
        });
    }

    var connection = mysql.createConnection(config);

    // Add handlers.
    addDisconnectHandler(connection);

    connection.connect();
    return connection;
}

연결 초기화 :

var connection = initializeConnection({
    host: "localhost",
    user: "user",
    password: "password"
});

사소한 제안 : 이것은 모든 사람에게 적용되는 것은 아니지만 범위와 관련된 사소한 문제에 부딪 혔습니다. OP가이 편집이 불필요하다고 생각하면 제거하도록 선택할 수 있습니다. 나를 위해, 나는의 라인 변경했다 initializeConnection이었다, var connection = mysql.createConnection(config);단순히로를

connection = mysql.createConnection(config);

그 이유는 if connection가 프로그램의 전역 변수 인 경우 이전에 문제 connection는 오류 신호를 처리 할 때 새 변수를 만들었 기 때문 입니다. 그러나 내 nodejs 코드에서 connection쿼리를 실행 하는 데 동일한 전역 변수를 계속 사용 했기 때문에 메서드 connection의 로컬 범위에서 새 변수 가 손실되었습니다 initalizeConnection. 그러나 수정시 전역 connection변수가 재설정되었는지 확인합니다. 다음과 같은 문제가 발생한 경우 관련이있을 수 있습니다.

치명적인 오류 후 쿼리를 대기열에 넣을 수 없습니다.

연결이 끊어진 후 쿼리를 수행 한 후 성공적으로 다시 연결 한 후 이것은 OP의 오타 일 수 있지만 명확히하고 싶었습니다.


1
멋진 코드이지만 내 스크립트는 addDisconectHandler 루틴을 입력하지 않고도 90 초 후에 종료 (코드 8)하는 것 같습니다. 아이디어?
emc apr

훌륭한 대답, 리팩터링 후 풀링을했지만 이것은 훌륭한 옵션입니다.
Pogrindis 2016 년

좋은 답변 감사합니다. 이것은 공식 문서의 일부 여야합니다 (개발자가 아닌 node-mysql에 의해 처리됨).
Skoua

1
이것은 환상적인 대답이지만 이것이 저를 위해 작동하기 위해 필요한 제안 / 조정이 있습니다. 이것이 모든 사람에게 필요할지 확실하지 않지만 이것은 확실히 도움이되었습니다. 지금까지 도움을 주셔서 감사합니다. 불필요하다고 생각되면 편집을 제거 할 수 있습니다.
Chris Gong

23

나는 같은 문제가 있었고 Google이 나를 여기로 인도했습니다. 을 제거하는 것이 옳지 않다는 @Ata에 동의합니다 end(). 더 많은 인터넷 검색이 끝나면 사용 pooling하는 것이 더 좋은 방법 이라고 생각 합니다.

풀링에 대한 node-mysql 문서

다음과 같습니다.

var mysql = require('mysql');
var pool  = mysql.createPool(...);

pool.getConnection(function(err, connection) {
    connection.query( 'bla bla', function(err, rows) {
        connection.release();
    });
});

7

함수 내에서 connect () 및 end ()를 사용하지 마십시오. 이로 인해 함수에 대한 반복 호출에 문제가 발생합니다. 연결 만

var connection = mysql.createConnection({
      host: 'localhost',
      user: 'node',
      password: 'node',
      database: 'node_project'
    })

connection.connect(function(err) {
    if (err) throw err

});

그 연결을 다시 사용하십시오.

기능 내부

function insertData(name,id) {

  connection.query('INSERT INTO members (name, id) VALUES (?, ?)', [name,id], function(err,result) {
      if(err) throw err
  });


}

5

AWS Lambda 함수

사용 mysql.createPool ()connection.destroy ()

이런 식으로 새 호출은 설정된 풀을 사용하지만 함수는 계속 실행되지 않습니다. 풀링의 모든 이점을 얻지 못하더라도 (각 새 연결은 기존 연결 대신 새 연결을 사용함) 두 번째 호출에서 이전 연결을 먼저 닫지 않고도 새 연결을 설정할 수 있습니다.

에 관해서 connection.end()

이로 인해 후속 호출에서 오류가 발생할 수 있습니다. 호출은 나중에 다시 시도하고 작동하지만 지연됩니다.

과 관련 mysql.createPool()하여connection.release()

Lambda 함수는 아직 열려있는 연결이 있기 때문에 예약 된 제한 시간까지 계속 실행됩니다.

코드 예

const mysql = require('mysql');

const pool = mysql.createPool({
  connectionLimit: 100,
  host:     process.env.DATABASE_HOST,
  user:     process.env.DATABASE_USER,
  password: process.env.DATABASE_PASSWORD,
});

exports.handler = (event) => {
  pool.getConnection((error, connection) => {
    if (error) throw error;
    connection.query(`
      INSERT INTO table_name (event) VALUES ('${event}')
    `, function(error, results, fields) {
      if (error) throw error;
      connection.destroy();
    });
  });
};

AWS Lambda 함수로 실행되는 NodeJS 스크립트가 있습니다. 데이터 세트가 끝날 때까지 다음 100 개를 검색하는 "다음"URL을 사용하여 한 번에 100 개의 레코드를 반환하는 Azure API를 ping합니다. 그래서 내 INSERT 함수는 여러 번 호출됩니다. connection.connect () 및 connection.end () 줄을 제거 할 때까지 "종료 후 핸드 셰이크를 대기열에 넣을 수 없습니다"오류가 발생했습니다. 대신 여기에서 풀을 사용하는 것이 더 합리적입니까? API에서 최종 데이터 세트가 반환 될 때 "connection.end ()"를 언제 호출
할지 모르겠습니다

2

의 인플레 이스 connection.connect();사용 -

if(!connection._connectCalled ) 
{
connection.connect();
}

이미 다음 호출되는 경우 connection._connectCalled =true,
및 그것은 실행되지 않습니다 connection.connect();

참고 -사용하지 마십시오connection.end();


1

이 문제는 내 것과 비슷하다고 생각합니다.

  1. MySQL에 연결
  2. MySQL 서비스 종료 (노드 스크립트를 종료하면 안 됨)
  3. MySQL 서비스 시작, 노드가 MySQL에 다시 연결
  4. DB 쿼리-> FAIL (치명적인 오류 후 쿼리를 대기열에 넣을 수 없습니다.)

Promise (q)를 사용하여 새로운 연결을 다시 만들어이 문제를 해결했습니다.

mysql-con.js

'use strict';
var config          = require('./../config.js');
var colors          = require('colors');
var mysql           = require('mysql');
var q               = require('q');
var MySQLConnection = {};

MySQLConnection.connect = function(){
    var d = q.defer();
    MySQLConnection.connection = mysql.createConnection({
        host                : 'localhost',
        user                : 'root',
        password            : 'password',
        database            : 'database'
    });

    MySQLConnection.connection.connect(function (err) {
        if(err) {
            console.log('Not connected '.red, err.toString().red, ' RETRYING...'.blue);
            d.reject();
        } else {
            console.log('Connected to Mysql. Exporting..'.blue);
            d.resolve(MySQLConnection.connection);
        }
    });
    return d.promise;
};

module.exports = MySQLConnection;

mysqlAPI.js

var colors          = require('colors');
var mysqlCon        = require('./mysql-con.js');
mysqlCon.connect().then(function(con){
   console.log('connected!');
    mysql = con;
    mysql.on('error', function (err, result) {
        console.log('error occurred. Reconneting...'.purple);
        mysqlAPI.reconnect();
    });
    mysql.query('SELECT 1 + 1 AS solution', function (err, results) {
            if(err) console.log('err',err);
            console.log('Works bro ',results);
    });
});

mysqlAPI.reconnect = function(){
    mysqlCon.connect().then(function(con){
      console.log("connected. getting new reference");
        mysql = con;
        mysql.on('error', function (err, result) {
            mysqlAPI.reconnect();
        });
    }, function (error) {
      console.log("try again");
        setTimeout(mysqlAPI.reconnect, 2000);
    });
};

이게 도움이 되길 바란다.


0

해결책 : 이 오류를 방지하려면 (AWS LAMBDA의 경우) :

"Nodejs 이벤트 루프"를 종료하려면 연결을 종료 한 다음 다시 연결해야합니다. 다음 코드를 추가하여 콜백을 호출합니다.

connection.end( function(err) {
        if (err) {console.log("Error ending the connection:",err);}

       //  reconnect in order to prevent the"Cannot enqueue Handshake after invoking quit"

         connection = mysql.createConnection({
                host     : 'rds.host',
                port     :  3306,
                user     : 'user',
               password : 'password',
               database : 'target database'

               });
        callback(null, {
            statusCode: 200,
            body: response,

        });
    });

람다 함수를 모두 호출하면 mysql 연결이 열리지 않습니까? 이것은 좋은 생각이 아니다 허용 대답 수행하는 또 다른 방법입니다
브라이언 맥콜을

1
아니. connection.end를 호출하면 루프가 완료되지만 데이터베이스에 대한 연결은 "연결 종료 중"상태로 유지됩니다. 새 연결을 열려고하면 항상 "종료를 호출 한 후 핸드 셰이크를 대기열에 넣을 수 없습니다"라는 오류가 발생하므로 실제로 추가 createConnection에서이 실패 오류가 발생하고 다음 연결은 실패하지 않았습니다. 이것은이 문제를 해결하는 방법 일뿐입니다. 사실 mysql 모듈은 더 깨끗한 연결 종료를 수행해야합니다.
Jorge Valvert

0

람다를 얻으려는 경우 처리기 context.done()를 끝내면 람다가 완료 된다는 것을 알았 습니다. 한 줄을 추가하기 전에 시간이 초과 될 때까지 실행되고 실행됩니다.


이것에 대한 코드 예제는?
Shafique

0

debug : false,

예 : // mysql 연결

var dbcon1 = mysql.createConnection({
      host: "localhost",
      user: "root",
      password: "",
      database: "node5",
      debug: false,
    });
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.