Node.js, Request, MySQL e Connection Pooling portano a Infinite Blocking / Freezing Behavior?

Sto lavorando su un servizio che si collega a un servizio REST, riceve una risposta, la trasforma e la scrive in un database. Inizialmente utilizzavo un file flat nel mio proof of concept e tutto ha funzionato bene. Ora, dopo 10-15 richieste, lo script si bloccherebbe. Stavo ricevendo tutte le 30 richieste per lavorare sul file flat e solo un terzo o la metà di quelle sul database.

Ho deciso di scrivere un test che isolasse ciò che stava succedendo e ho scoperto che dopo aver eliminato tutta la mia effettiva logica applicativa, lo schema del database e le informazioni sulla richiesta, sono arrivato a qualcosa del genere:

var mysql = require('mysql'); var pool = mysql.createPool({ host : 'localhost', user : 'user', password : 'secret', }); while (true) { pool.getConnection(function (err, connection) { if (err) throw err; connection.query('SELECT 1 + 1 AS solution', function(err, rows, fields) { if (err) throw err; console.log('The solution is: ', rows[0].solution); connection.end(); }); }); } 

Per quanto posso immaginare, questa è la quantità minima di codice per fare qualcosa usando un pool di connessioni. Quando viene eseguito, nulla viene mai registrato sulla riga di comando. Rimuove il blocco while {} e viene eseguito una volta come previsto, quindi esce.

La mia aspettativa era che la dimensione del pool avrebbe fornito il vincolo, e mentre avrebbe interrogato mysql abbastanza rapidamente, non sarebbe mai cresciuto oltre una certa dimensione. Invece, sembra non tentare mai di stabilire una connessione.


Modifiche basate sul commento di Daniel sulla libreria asincrona e su quando chiamare connection.end() . Seguo la logica dietro ciò che la libreria async sta ottenendo qui e che dovresti rilasciare la risorsa il prima ansible, ma qualcosa sta ancora bloccando. Stampa il risultato della query sulla console una volta, quindi “si blocca”.

     var mysql = require('mysql'), async = require('async'); var pool = mysql.createPool({ host : 'localhost', user : 'user', password : 'secret', }); async.forever(function() { pool.getConnection(function (err, connection) { if(err) throw err; connection.query('SELECT 1 + 1 AS solution', function(err, rows, fields) { connection.end(); if (err) throw err; console.log('The solution is: ', rows[0].solution); }); }); }, function (err) { console.log(err); }); 

    Non mi sento a mio agio ad essere bloccato in questo modo – sembra che async o mysql stiano rompendo la promise di essere asincroni … qualche pensiero?

    Stai utilizzando un ciclo sincrono per distribuire una risorsa asincrona. Non puoi farlo.

    Il tuo ciclo while riempie il pool di database e quindi loop ancora una volta e blocca su getConnection che blocca quindi l’intero ciclo degli eventi di Node.js.

    È ansible utilizzare il pacchetto async per eseguire cicli asincroni durante l’esecuzione.

    La chiamata asincrona # per sempre farebbe ciò che stai cercando di ottenere.


    Inoltre, il tuo codice perde connessioni al database. Dovresti mettere la connection.end() prima nella callback a meno che non usi di nuovo la stessa connessione. In caso contrario, un errore perderà una connessione al database.

     pool.getConnection(function (err, connection) { if (err) throw err; connection.query('SELECT 1 + 1 AS solution', function(err, rows, fields) { connection.end(); // return to pool before evaluating error. if (err) throw err; console.log('The solution is: ', rows[0].solution); }); }); 

    Ho trovato quello che stavo facendo di sbagliato con async.forever , grazie a questo eccellente articolo sull’uso pratico della libreria async: http://www.sebastianseilund.com/nodejs-async-in-practice

    La chiave è capire come async utilizza le sue funzioni di callback speciali. Deve essere passato alla funzione asincrona interna più nidificata come parametro di callback, in modo che la funzione possa passare il controllo a asincrono. Ecco la sceneggiatura che ho revisionato basandomi sul feedback di Daniel dall’alto, corretto per usare correttamente la libreria (e funziona come previsto):

     var mysql = require('mysql'), async = require('async'); var pool = mysql.createPool({ host : 'localhost', user : 'user', password : 'secret', }); async.forever(function(callback) { pool.getConnection(function (err, connection) { if(err) throw err; connection.query('SELECT 1 + 1 AS solution', function(err, rows, fields) { connection.end(callback); if (err) throw err; console.log('The solution is: ', rows[0].solution); }); }); }, function (err) { console.log(err); });