98 votes

Impossible de mettre en file d'attente Handshake après avoir invoqué quit

J'ai mis en œuvre le code suivant :

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();
    }
}

Tout fonctionne très bien, mais seulement pour la première fois. Si je veux "utiliser" la requête pour la deuxième fois, j'obtiens l'erreur suivante :

Cannot enqueue Handshake after invoking quit

J'ai essayé de ne pas .end() des connexions mais ça n'a pas aidé.

Comment puis-je résoudre ce problème ?

279voto

Andrew Rhyne Points 1259

Si vous utilisez le module node-mysql, supprimez simplement le .connect et le .end. Je viens de résoudre le problème moi-même. Apparemment, ils ont introduit du code inutile dans leur dernière itération qui est également bogué. Vous n'avez pas besoin de vous connecter si vous avez déjà exécuté l'appel createConnection.

64voto

XP1 Points 1647

Selon :

TL;DR Vous devez établir une nouvelle connexion en appelant la fonction createConnection après chaque déconnexion.

et

Note : Si vous répondez à des requêtes web, vous ne devriez pas terminer les connexions à chaque requête. Créez simplement une connexion au et utilisez l'objet connexion/client pour effectuer des requêtes en permanence. Vous pouvez écouter l'événement d'erreur pour gérer la déconnexion du serveur et pour la reconnexion. Code complet aquí .


De :

C'est écrit :

Le serveur se déconnecte

Vous pouvez perdre la connexion à un serveur MySQL en raison de problèmes de réseau, d'un retard du serveur ou d'un plantage du serveur. Tous ces événements sont considérés comme des erreurs fatales, et auront le err.code = 'PROTOCOL_CONNECTION_LOST' . Voir l'erreur pour plus d'informations.

La meilleure façon de gérer ces déconnexions inattendues est indiquée ci-dessous :

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);

Comme vous pouvez le voir dans l'exemple ci-dessus, la reconnexion d'une connexion est s'effectue en établissant une nouvelle connexion. Une fois terminée, une existant ne peut pas être reconnecté par conception.

Avec le pool, les connexions déconnectées seront retirées du pool. libérant ainsi de l'espace pour la création d'une nouvelle connexion lors de la prochaine session de l'opération de l'appel de connexion suivant.


J'ai modifié la fonction de sorte que chaque fois qu'une connexion est nécessaire, une fonction d'initialisation ajoute automatiquement les gestionnaires :

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;
}

Initialisation d'une connexion :

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

Petite suggestion : Cela ne s'applique peut-être pas à tout le monde, mais j'ai rencontré un petit problème lié à la portée. Si le PO pense que cette modification n'était pas nécessaire, il peut choisir de la supprimer. Pour ma part, j'ai dû modifier une ligne dans le fichier initializeConnection qui a été var connection = mysql.createConnection(config); pour simplement

connection = mysql.createConnection(config);

La raison étant que si connection est une variable globale dans votre programme, alors le problème précédent était que vous faisiez une nouvelle connection lors du traitement d'un signal d'erreur. Mais dans mon code nodejs, je continue d'utiliser la même variable globale connection pour exécuter des requêtes, de sorte que la nouvelle variable connection serait perdue dans la portée locale de l initalizeConnection méthode. Mais lors de la modification, il s'assure que le global connection est réinitialisée Cela peut être pertinent si vous rencontrez un problème connu sous le nom de

Impossible de mettre en file d'attente une requête après une erreur fatale

après avoir essayé d'exécuter une requête après avoir perdu la connexion, puis s'être reconnecté avec succès. Il s'agit peut-être d'une faute de frappe de l'OP, mais je tenais à le préciser.

26voto

hbrls Points 953

J'ai eu le même problème et Google m'a conduit ici. Je suis d'accord avec @Ata pour dire que ce n'est pas bien de juste supprimer end() . Après une recherche plus approfondie sur Google, je pense qu'utiliser pooling est un meilleur moyen.

Document sur le pooling dans node-mysql

C'est comme ça :

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

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

7voto

ajin Points 364

Ne pas connecter() et terminer() à l'intérieur de la fonction. Cela causerait des problèmes lors d'appels répétés de la fonction. Effectuez la connexion uniquement

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

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

});

une fois et réutiliser cette connexion.

Dans la fonction

function insertData(name,id) {

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

}

7voto

James Nuanez Points 192

Fonctions Lambda AWS

Utilisez mysql.createPool() con connexion.destroy()

De cette façon, les nouvelles invocations utilisent le pool établi, mais ne maintiennent pas la fonction en cours d'exécution. Même si vous ne bénéficiez pas de tous les avantages de la mise en commun (chaque nouvelle connexion utilise une nouvelle connexion au lieu d'une connexion existante), cela permet à une deuxième invocation d'établir une nouvelle connexion sans devoir fermer la précédente au préalable.

Concernant connection.end()

Cela peut provoquer une erreur lors d'une invocation ultérieure. L'invocation sera quand même réessayée plus tard et fonctionnera, mais avec un retard.

Concernant mysql.createPool() con connection.release()

La fonction Lambda continuera à s'exécuter jusqu'au délai d'expiration prévu, car il y a toujours une connexion ouverte.

Exemple de code

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();
    });
  });
};

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X