mongoError: Topologia została zniszczona

163

Mam usługę REST wbudowaną w node.js z Restify i Mongoose oraz mongoDB z kolekcją około 30 000 dokumentów o normalnym rozmiarze. Mam usługę węzła działającą przez pmx i pm2.

Wczoraj nagle węzeł zaczął wyrzucać błędy komunikatem „MongoError: Topology was zniszczona”, nic więcej. Nie mam pojęcia, co to oznacza i co mogło to spowodować. nie ma też wiele do znalezienia podczas wyszukiwania w Google. Więc pomyślałem, że zapytam tutaj.

Po dzisiejszym ponownym uruchomieniu usługi węzła błędy przestały pojawiać się. Jeden z nich również mam uruchomione w środowisku produkcyjnym i przeraża mnie, że może się to zdarzyć w dowolnym momencie w dość istotnej części instalacji, która tam działa ...

Używam następujących wersji wspomnianych pakietów:

  • mangusta: 4.0.3
  • restify: 3.0.3
  • węzeł: 0.10.25
dreagan
źródło
2
Mam podobne problemy używając tylko sterownika mongodb :(
0x8890
1
Nie używam żagli, więc nie, nie sądzę, żeby to rozwiązało mój problem
dreagan.

Odpowiedzi:

98

Wygląda na to, że połączenie serwera węzłowego z instancją MongoDB zostało przerwane podczas próby zapisu do niej.

Spójrz na kod źródłowy Mongo, który generuje ten błąd

Mongos.prototype.insert = function(ns, ops, options, callback) {
    if(typeof options == 'function') callback = options, options = {};
    if(this.s.state == DESTROYED) return callback(new MongoError(f('topology was destroyed')));
    // Topology is not connected, save the call in the provided store to be
    // Executed at some point when the handler deems it's reconnected
    if(!this.isConnected() && this.s.disconnectHandler != null) {
      callback = bindToCurrentDomain(callback);
      return this.s.disconnectHandler.add('insert', ns, ops, options, callback);
    }

    executeWriteOperation(this.s, 'insert', ns, ops, options, callback);
}

Wygląda na to, że nie ma to związku z problemem Sails wymienionym w komentarzach, ponieważ nie zainstalowano żadnych aktualizacji, aby przyspieszyć awarię lub „naprawić”

Jason Nichols
źródło
2
Mam ten sam problem i zdarza się to prawie co tydzień i wyłącza aplikację pracującą z mongo, czy to jakiś problem, który wygenerowałem, czy to jest problem w Mongoose?
Mohammad Ganji
@MohammadGanji: Otrzymuję ten błąd bez Mongoose, podczas debugowania kodu klienta i nie jestem wystarczająco szybki w przekraczaniu instrukcji. Nie jestem pewien, co to powoduje, ale ustawienie punktów przerwania zaraz po zapytaniach mongo pozwala tego uniknąć.
Dan Dascalescu
@DanDascalescu Zapomniałem wspomnieć, że mój problem został rozwiązany, był to problem z logowaniem, wygląda na to, że w logach pojawiło się ostrzeżenie, że po pewnym czasie zajęło to około gigabajta pamięci i zamknąłem proces mongo, więc spróbowałem spakować i wykonać kopię zapasową i problem rozwiązany
Mohammad Ganji
83

Wiem, że odpowiedź Jasona została zaakceptowana, ale miałem ten sam problem z Mongoose i stwierdziłem, że usługa hostująca moją bazę danych zalecała zastosowanie następujących ustawień , aby utrzymać połączenie Mongodb w środowisku produkcyjnym:

var options = {
  server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
  replset: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } }
};
mongoose.connect(secrets.db, options);

Mam nadzieję, że ta odpowiedź może pomóc innym osobom mającym błędy „Topologia została zniszczona”.

Adrien Joly
źródło
4
To nie rozwiązało problemu. Skończyło się na zwiększeniu mojego KeepAlive do 30000, co bardzo pomogło. Mimo że nadal pojawia się sporadyczny błąd topologii.
ifightcrime
9
używając sterownika Mongo od wersji 3.4.2, te opcje muszą być na najwyższym poziomie: options: {keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000}
Sebastien H.
Ten błąd pojawia się bez Mongoose, podczas debugowania kodu klienta i niedostatecznej szybkości przechodzenia przez instrukcje. Nie jestem pewien, co to powoduje, ale ustawienie punktów przerwania zaraz po zapytaniach mongo pozwala tego uniknąć.
Dan Dascalescu
76

Ten błąd jest spowodowany przerwaniem połączenia przez sterownik mongo z dowolnego powodu (na przykład awaria serwera).

Domyślnie mongoose spróbuje połączyć się ponownie przez 30 sekund, a następnie przestanie ponawiać próby i na zawsze wyrzuci błędy, aż do ponownego uruchomienia.

Możesz to zmienić, edytując te 2 pola w opcjach połączenia

mongoose.connect(uri, 
    { server: { 
        // sets how many times to try reconnecting
        reconnectTries: Number.MAX_VALUE,
        // sets the delay between every retry (milliseconds)
        reconnectInterval: 1000 
        } 
    }
);

dokumentacja opcji połączeń

gafi
źródło
3
Tak. Technicznie przyjęta odpowiedź odpowiada na zadane pytanie, ALE jest to właściwy sposób na uniknięcie omawianego scenariusza.
kingdango
3
używając sterownika Mongo z wersji 3.4.2, te opcje muszą znajdować się na najwyższym poziomie: options: {keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 2000}
Sebastien H.
1
Aby wyjaśnić, zgodnie z dokumentacją sterownika Node MongoDB , serwer domyślnie próbowałby połączyć się ponownie 30 razy, z jednosekundową przerwą między kolejnymi próbami.
Boaz
4
Nie musisz teraz podawać tych opcji w obiekcie serwera. Przechodzi bezpośrednio do obiektów opcji.
Animesh Singh
3
Chciałem tylko dodać, że najnowsze wersje mangusty mają te opcje na najwyższym poziomie, więc nie ma potrzeby dodawania server: {itp.
Alex K,
17

W moim przypadku ten błąd był spowodowany przez db.close();sekcję „await” w „async”

MongoClient.connect(url, {poolSize: 10, reconnectTries: Number.MAX_VALUE, reconnectInterval: 1000}, function(err, db) {
    // Validate the connection to Mongo
    assert.equal(null, err);    
    // Query the SQL table 
    querySQL()
    .then(function (result) {
        console.log('Print results SQL');
        console.log(result);
        if(result.length > 0){

            processArray(db, result)
            .then(function (result) {
                console.log('Res');
                console.log(result);
            })
            .catch(function (err) {
                console.log('Err');
                console.log(err);
            })
        } else {
            console.log('Nothing to show in MySQL');
        }
    })
    .catch(function (err) {
        console.log(err);
    });
    db.close(); // <--------------------------------THIS LINE
});
Carlos Rodríguez
źródło
2
W przypadku Carlosa myślę, że zakończenie nastąpiło przed wszystkim innym. Mój przypadek był podobny: uzyskałem dostęp do bazy danych po jej zamknięciu. Byłoby miło, gdyby programiści Mongo mogli generować bardziej wyraźne komunikaty o błędach. „Uszkodzona topologia” brzmi jak nuta wewnętrzna.
Juan Lanus,
3
Twoim rozwiązaniem było przeniesienie budynku db.closedo thenbloku, prawda?
AlexChaffee
To prawda, w moim przypadku usuwam tylko linię db.close (), ale przenoszę ją do bloku then, wydaje się być dobrym rozwiązaniem.
Carlos Rodríguez
1
Przeniesienie db.closedo thenbloku działało świetnie z natywnym sterownikiem MongoDB Node.js.
kevinmicke
12

To tylko niewielki dodatek do odpowiedzi Gaafara, dało mi to ostrzeżenie o dezaprobacie. Zamiast w obiekcie serwera, na przykład:

MongoClient.connect(MONGO_URL, {
    server: {
        reconnectTries: Number.MAX_VALUE,
        reconnectInterval: 1000
    }
});

Może wejść na obiekt najwyższego poziomu. Po prostu wyjmij go z obiektu serwera i umieść w obiekcie opcji w następujący sposób:

MongoClient.connect(MONGO_URL, {
    reconnectTries: Number.MAX_VALUE,
    reconnectInterval: 1000
});
Codeinaire
źródło
7

„Topologia została zniszczona” może być spowodowana odłączeniem się mangusty przed utworzeniem indeksów dokumentów mongo, zgodnie z tym komentarzem

Aby upewnić się, że wszystkie modele mają utworzone indeksy przed odłączeniem, możesz:

await Promise.all(mongoose.modelNames().map(model => mongoose.model(model).ensureIndexes()));

await mongoose.disconnect();
golfadas
źródło
dziękuję, jeśli prowadzisz przypadki testowe - to prawdopodobnie bardzo prawdopodobna odpowiedź ...
Nick H247
1
To było to dla mnie. Dziękuję Ci! Przeprowadzałem testy w Jest z serwerem pamięci mongodb, otrzymując sporadyczne błędy w topologii lub otwarte dojścia / niedokończone obietnice. Ale czasami to działało. Dodanie oczekiwania na indeksy naprawiło ten problem.
roblingle
Otrzymuję ten błąd bez Mongoose, podczas debugowania kodu Jest, takiego jak @roblingle, i nie jest wystarczająco szybki w przechodzeniu przez instrukcje. Nie jestem pewien, co to powoduje, ale ustawienie punktów przerwania zaraz po zapytaniach mongo pozwala tego uniknąć.
Dan Dascalescu
@roblingle, jak ostatecznie to naprawiłeś? Właśnie napotkałem ten problem i uniemożliwił mi ponowne połączenie z MongoDB. Od tego czasu usunąłem wszystko i ponownie zainstalowałem MongoDB (przez homebrew), a teraz nie będzie już działać podczas uruchamiania. (Może to być kwestia niezwiązana)
bobbyz
Brzmi niezwiązane. Moja aplikacja działała dobrze, ale testy kończyły się niepowodzeniem.
roblingle
3

Komentarz Sebastiana do odpowiedzi Adriena wymaga więcej uwagi, pomógł mi, ale może być czasem zignorowany, więc oto rozwiązanie :

var options =  { useMongoClient: true, keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000 }
mongoose.connect(config.mongoConnectionString, options, (err) => {
    if(err) {
        console.error("Error while connecting", err);
    }
});
Czarna Mamba
źródło
2

Ja też miałem ten sam błąd. W końcu odkryłem, że mam jakiś błąd w moim kodzie. Używam równoważenia obciążenia dla dwóch serwerów nodejs, ale po prostu aktualizuję kod jednego serwera.

Zmieniam serwer mongod from standalone to replication, ale zapomniałem wykonać odpowiednią aktualizację parametrów połączenia, więc napotkałem ten błąd.

autonomiczne parametry połączenia: parametry mongodb://server-1:27017/mydb połączenia replikacji: mongodb://server-1:27017,server-2:27017,server-3:27017/mydb?replicaSet=myReplSet

szczegóły tutaj :[dokument mongo dotyczący parametrów połączenia]

lutaoact
źródło
2

Spotkałem to w środowisku kubernetes / minikube + nodejs + mongoose. Problem polegał na tym, że usługa DNS działała z pewnym opóźnieniem. Sprawdzanie, czy DNS jest gotowy, rozwiązało mój problem.

const dns = require('dns');

var dnsTimer = setInterval(() => {
	dns.lookup('mongo-0.mongo', (err, address, family) => {
		if (err) {
			console.log('DNS LOOKUP ERR', err.code ? err.code : err);
		} else {
			console.log('DNS LOOKUP: %j family: IPv%s', address, family);
			clearTimeout(dnsTimer);
			mongoose.connect(mongoURL, db_options);
		}
	});
}, 3000);


var db = mongoose.connection;
var db_options = {
	autoReconnect:true,

	poolSize: 20,
	socketTimeoutMS: 480000,
	keepAlive: 300000,

	keepAliveInitialDelay : 300000,
	connectTimeoutMS: 30000,
	reconnectTries: Number.MAX_VALUE,
	reconnectInterval: 1000,
	useNewUrlParser: true
};

(liczby w opcji db_options są arbitralne w przypadku stackoverflow i podobnych witryn)

tkrizsa
źródło
2

Tutaj to, co zrobiłem, działa dobrze. Problem zniknął po dodaniu poniższych opcji.

const dbUrl = "mongodb://localhost:27017/sampledb";
const options =  { useMongoClient: true, keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000, useNewUrlParser: true }
mongoose.connect(dbUrl,options, function(
  error
) {
  if (error) {
    console.log("mongoerror", error);
  } else {
    console.log("connected");
  }

});
Thavaprakash Swaminathan
źródło
2

Musisz ponownie uruchomić mongo, aby rozwiązać błąd topologii, a następnie po prostu zmienić niektóre opcje mangusty lub mongoclienta, aby rozwiązać ten problem:

var mongoOptions = {
    useMongoClient: true,
    keepAlive: 1,
    connectTimeoutMS: 30000,
    reconnectTries: Number.MAX_VALUE,
    reconnectInterval: 5000,
    useNewUrlParser: true
}

mongoose.connect(mongoDevString,mongoOptions);
Ganesh Sharma
źródło
Witamy w SO! Edytuj swoją odpowiedź i dodaj więcej informacji, tj. Jak rozwiązuje problem, aby uzyskać więcej wskazówek, patrz stackoverflow.com/help/how-to-ask
B - rian
1

Otrzymałem ten błąd podczas tworzenia nowej bazy danych w społeczności MongoDb Compass. Problem był z moim Mongodem, nie działał. Aby rozwiązać problem, musiałem uruchomić polecenie Mongod jak poprzednio.

C:\Program Files\MongoDB\Server\3.6\bin>mongod

Po uruchomieniu tego polecenia udało mi się stworzyć bazę danych.

Mam nadzieję, że to pomoże.

Sibeesh Venu
źródło
1

Od jakiegoś czasu się z tym zmagałem - jak widać na podstawie innych odpowiedzi, problem może być bardzo różny.

Najłatwiejszym sposobem, aby dowiedzieć się, co powoduje, jest włączenie loggerLevel: 'info'w opcjach

orepor
źródło
0

W moim przypadku ten błąd był spowodowany przez identyczną instancję serwera, która już działa w tle.

Dziwne jest to, że kiedy uruchomiłem swój serwer bez powiadomienia, jeden już działa, konsola nie wyświetlała niczego w stylu „coś używa portu xxx”. Mógłbym nawet wrzucić coś na serwer. Tak więc zlokalizowanie tego problemu zajęło mi dość dużo czasu.

Co więcej, po zamknięciu wszystkich aplikacji, które mogę sobie wyobrazić, nadal nie mogłem znaleźć procesu używającego tego portu w monitorze aktywności mojego Maca. Muszę użyć lsofdo śledzenia. Sprawca nie był zaskakujący - to proces węzłowy. Jednak z PID pokazanym na terminalu stwierdziłem, że numer portu na monitorze różni się od tego używanego przez mój serwer.

Podsumowując, zabicie wszystkich procesów węzłów może bezpośrednio rozwiązać ten problem.

AnLuoRidge
źródło
-3

Rozwiązałem ten problem poprzez:

  1. zapewnienie działania mongo
  2. ponowne uruchamianie mojego serwera
maia
źródło
4
Nie przeszkadza to w ponownym wystąpieniu problemu
Sam Munroe