nodejs mysql Błąd: utracono połączenie Serwer zamknął połączenie

89

kiedy używam węzła mysql, pojawia się błąd między 12:00 a 2:00, że połączenie TCP jest zamykane przez serwer. Oto pełna wiadomość:

Error: Connection lost: The server closed the connection.
at Protocol.end (/opt/node-v0.10.20-linux-x64/IM/node_modules/mysql/lib/protocol/Protocol.js:73:13)
at Socket.onend (stream.js:79:10)
at Socket.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:920:16
at process._tickCallback (node.js:415:13)

Jest rozwiązanie . Jednak po tym, jak spróbuję w ten sposób, problem też się pojawia. teraz nie wiem, jak to zrobić. Czy ktoś napotyka ten problem?

Oto sposób, w jaki napisałem, postępuj zgodnie z rozwiązaniem:

    var handleKFDisconnect = function() {
    kfdb.on('error', function(err) {
        if (!err.fatal) {
            return;
        }
        if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
            console.log("PROTOCOL_CONNECTION_LOST");
            throw err;
        }
        log.error("The database is error:" + err.stack);

        kfdb = mysql.createConnection(kf_config);

        console.log("kfid");

        console.log(kfdb);
        handleKFDisconnect();
    });
   };
   handleKFDisconnect();
jackieLin
źródło

Odpowiedzi:

160

Spróbuj użyć tego kodu do obsługi rozłączania serwera:

var db_config = {
  host: 'localhost',
    user: 'root',
    password: '',
    database: 'example'
};

var connection;

function handleDisconnect() {
  connection = mysql.createConnection(db_config); // Recreate the connection, since
                                                  // the old one cannot be reused.

  connection.connect(function(err) {              // The server is either down
    if(err) {                                     // or restarting (takes a while sometimes).
      console.log('error when connecting to db:', err);
      setTimeout(handleDisconnect, 2000); // We introduce a delay before attempting to reconnect,
    }                                     // to avoid a hot loop, and to allow our node script to
  });                                     // process asynchronous requests in the meantime.
                                          // If you're also serving http, display a 503 error.
  connection.on('error', function(err) {
    console.log('db error', err);
    if(err.code === 'PROTOCOL_CONNECTION_LOST') { // Connection to the MySQL server is usually
      handleDisconnect();                         // lost due to either server restart, or a
    } else {                                      // connnection idle timeout (the wait_timeout
      throw err;                                  // server variable configures this)
    }
  });
}

handleDisconnect();

W twoim kodzie brakuje mi części po connection = mysql.createConnection(db_config);

PochmurnoMarmur
źródło
ok, spróbuję tego. ale jak mógłbym zasymulować tę sytuację
jackieLin
1
Wskazówka: testuję ponowne połączenie, uruchamiając ponownie usługę mysql, aby upewnić się, że wszystko działa dobrze.
kriskodzi
2
@jackieLin można symulować sytuację, ponowne uruchomienie usługi mysql na Ubuntu sudo mysql restart usług
Igor
1
Dziękuję @ user3073745, ten problem został rozwiązany przez restart
jackieLin
1
Działa idealnie dla węzła 8. *, npm 5.6.0 i mysql: 5.7 ... Dzięki !!
JRichardsz
47

Nie przypominam sobie mojego pierwotnego przypadku użycia tego mechanizmu. W dzisiejszych czasach nie mogę wymyślić żadnego ważnego przypadku użycia.

Twój klient powinien być w stanie wykryć utratę połączenia i umożliwić ponowne utworzenie połączenia. Jeśli ważne jest, aby część logiki programu była wykonywana przy użyciu tego samego połączenia, użyj transakcji.

tl; dr; Nie używaj tej metody.


Pragmatycznym rozwiązaniem jest wymuszenie na MySQL utrzymania połączenia:

setInterval(function () {
    db.query('SELECT 1');
}, 5000);

Wolę to rozwiązanie od puli połączeń i obsługi rozłączania, ponieważ nie wymaga ono strukturyzowania kodu w sposób świadomy obecności połączenia. Wykonywanie zapytania co 5 sekund gwarantuje, że połączenie pozostanie aktywne i PROTOCOL_CONNECTION_LOSTnie nastąpi.

Ponadto ta metoda zapewnia utrzymanie tego samego połączenia , w przeciwieństwie do ponownego łączenia. To jest ważne. Zastanów się, co by się stało, gdyby Twój skrypt opierał się na skrypcie LAST_INSERT_ID()i połączenie mysql zostało zresetowane bez Twojej wiedzy?

Jednak zapewnia to tylko, że limit czasu połączenia ( wait_timeouti interactive_timeout) nie wystąpi. Zgodnie z oczekiwaniami zakończy się niepowodzeniem we wszystkich innych scenariuszach. Dlatego pamiętaj o obsłudze innych błędów.

Gajus
źródło
1
Ciekawe, gdzie umieściłbyś to zapytanie db? Na dole serwera nodejs, prawda? Jedynym problemem jest to, że używam mysql do uwierzytelnienia użytkownika tylko raz, a następnie przechowuję jego dane w tymczasowym obiekcie użytkownika dla mojej gry RPG. Nie wiem, dlaczego mam dzisiaj losowo ten błąd zamknięty mysql, hmm. Prawidłowo zamykam połączenie itp. Też.
NiCk Newman
1
Powinieneś łączyć się z bazą danych i rozłączać na żądanie. To rozwiązanie jest przeznaczone dla usług, które działają w sposób ciągły i przez cały czas korzystają z połączenia z bazą danych.
Gajus
1
Żadne z nich nie brzmi prawdopodobnie, biorąc pod uwagę, że twój kod jest zgodny z opisanym wzorcem (coś podobnego do gist.github.com/gajus/5bcd3c7ec5ddcaf53893 ). Gdyby zdarzyło się to tylko raz lub dwa razy na tysiące zapytań, założyłbym problemy z łącznością, przeciążenie serwera lub coś podobnego.
Gajus
2
To była prawdopodobnie najgorsza sugestia! Osoba sugerująca, że ​​powinieneś wbić bazę danych zapytaniami tylko po to, aby połączenie nie zostało przerwane? Co się stanie, jeśli zrobi to 100 osób? lub dlaczego nie 10 000, jeśli aplikacja odnotowuje, wątek powinien zostać zwrócony do puli wątków MYSQL, NIE przejmując wątku, aby twój słaby kod nie pękł !, w tym przypadku zaimplementujesz funkcję ponownego połączenia, jeśli takie zdarzenie wystąpiło ! To niewiarygodne, to takie stu *** dzięki Bogu, że FB nie miał cię jako głównego architekta !!
Patrik Forsberg
2
Zaktualizowałem odpowiedź, aby odzwierciedlić, że nie polecam tego podejścia. Dzięki za ostrzeżenie Patrik.
Gajus
3

Lepszym rozwiązaniem jest skorzystanie z basenu - źle sobie z tym poradzę.

const pool = mysql.createPool({
  host: 'localhost',
  user: '--',
  database: '---',
  password: '----'
});

// ... later
pool.query('select 1 + 1', (err, rows) => { /* */ });

https://github.com/sidorares/node-mysql2/issues/836

Lalgulab Khatkar
źródło
1

Tworzenie i niszczenie połączeń w każdym zapytaniu może być skomplikowane, miałem kłopoty z migracją serwera, kiedy zdecydowałem się zainstalować MariaDB zamiast MySQL. Z jakiegoś powodu w pliku etc / my.cnf parametr wait_timeout miał domyślną wartość 10 sekund (powoduje to, że utrwalenia nie można zaimplementować). Następnie rozwiązanie zostało ustawione na 28800, czyli 8 godzin. Cóż, mam nadzieję, że pomogę komuś z tą "güevonada" ... przepraszam za mój słaby angielski.

Aleks Towers
źródło