mongoError: la topología fue destruida

163

Tengo un servicio REST integrado en node.js con Restify y Mongoose y un mongoDB con una colección con aproximadamente 30,000 documentos de tamaño regular. Tengo mi servicio de nodo ejecutándose a través de pmx y pm2.

Ayer, de repente, el nodo comenzó a eliminar errores con el mensaje "MongoError: se destruyó la topología", nada más. No tengo idea de qué se entiende por esto y qué podría haber desencadenado esto. tampoco hay mucho que encontrar al buscar en google esto. Así que pensé en preguntar aquí.

Después de reiniciar el servicio de nodo hoy, los errores dejaron de aparecer. También tengo uno de estos ejecutándose en producción y me da miedo que esto pueda suceder en cualquier momento en una parte crucial de la configuración que se ejecuta allí ...

Estoy usando las siguientes versiones de los paquetes mencionados:

  • mangosta: 4.0.3
  • restify: 3.0.3
  • nodo: 0.10.25
soñar
fuente
2
Tengo problemas similares usando solo el controlador mongodb :(
0x8890
1
No estoy usando velas, así que no, no creo que eso solucione mi problema
dreagan

Respuestas:

98

Parece que significa que la conexión de su servidor de nodo a su instancia de MongoDB se interrumpió mientras intentaba escribir en ella.

Eche un vistazo al código fuente de Mongo que genera ese error

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

Esto no parece estar relacionado con el problema de Sails citado en los comentarios, ya que no se instalaron actualizaciones para precipitar el bloqueo o la "solución"

Jason Nichols
fuente
2
Tengo el mismo problema y ocurre casi todas las semanas y cierra la aplicación que funciona con mongo, ¿es este un problema que generé o es un problema en mangosta?
Mohammad Ganji
@MohammadGanji: Recibo este error sin Mongoose, mientras depuro el código del cliente y no soy lo suficientemente rápido para pasar por alto las declaraciones. No estoy seguro de qué lo causa, pero establecer puntos de interrupción justo después de las consultas de mongo lo evita.
Dan Dascalescu
@DanDascalescu Olvidé mencionar que mi problema se resolvió, era un problema con el registro, parece que hubo alguna advertencia en los registros que después de algún tiempo tomó alrededor de un gigabyte de almacenamiento y cerró el proceso de mongo, así que intenté comprimir y hacer copias de seguridad y problema resuelto
Mohammad Ganji
83

Sé que la respuesta de Jason fue aceptada, pero tuve el mismo problema con Mongoose y descubrí que el servicio que hospedaba mi base de datos me recomendaba aplicar la siguiente configuración para mantener viva la conexión de Mongodb en producción:

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

Espero que esta respuesta pueda ayudar a otras personas que tienen errores de "Se destruyó la topología".

Adrien Joly
fuente
44
Esto no solucionó el problema para mí. De hecho, terminé aumentando mi keepAlive a 30000, lo que me ha ayudado enormemente. A pesar de que todavía recibo el error ocasional de la topología, sigo apareciendo.
ifightcrime
9
utilizando el controlador Mongo de la versión 3.4.2, estas opciones deben estar en el nivel superior: opciones: {keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000}
Sebastien H.
Obtengo este error sin Mongoose, mientras depuro el código del cliente y no soy lo suficientemente rápido para pasar por alto las declaraciones. No estoy seguro de qué lo causa, pero establecer puntos de interrupción justo después de las consultas de mongo lo evita.
Dan Dascalescu
76

Este error se debe a que el controlador mongo desconectó la conexión por cualquier motivo (por ejemplo, el servidor no funcionaba).

De forma predeterminada, mangosta intentará volver a conectarse durante 30 segundos, luego dejará de volver a intentarlo y arrojará errores para siempre hasta que se reinicie.

Puede cambiar esto editando estos 2 campos en las opciones de conexión

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

documentación de opciones de conexión

gafi
fuente
3
Sí. Técnicamente, la respuesta aceptada responde a la pregunta PERO esta es la forma correcta de evitar el escenario en discusión.
kingdango
3
utilizando el controlador Mongo de la versión 3.4.2, estas opciones deben estar en el nivel superior: opciones: {keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 2000}
Sebastien H.
1
Para aclarar, de acuerdo con la documentación del controlador Node MongoDB , por defecto el servidor intentaría reconectarse 30 veces, con un segundo de diferencia entre cada reintento.
Booz
44
No necesita proporcionar estas opciones bajo el objeto del servidor ahora. Va directamente a los objetos de opciones.
Animesh Singh
3
Solo quería agregar que las versiones recientes de mangosta tienen esas opciones en el nivel superior, por lo que no es necesario agregar, server: {etc.
Alex K
17

En mi caso, este error fue causado por una db.close();sección fuera de 'esperar' dentro de '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
fuente
2
En el caso de Carlos, supongo que el cierre ocurrió antes que todo lo demás. Mi caso fue similar: accedí al DB después de haberlo cerrado. Sería bueno si los desarrolladores de Mongo pudieran producir mensajes de error más explícitos. La "topología rota" suena como una nota interna.
Juan Lanus
3
su solución era mover la db.closeen un thenbloque, ¿verdad?
AlexChaffee
Es correcto, en mi caso solo elimino la línea db.close (), pero moverla a un bloque de entonces parece ser una buena solución.
Carlos Rodríguez
1
Moverlo db.closea un thenbloque funcionó muy bien para mí con el controlador nativo de MongoDB Node.js.
kevinmicke
12

Solo una pequeña adición a la respuesta de Gaafar, me dio una advertencia de desaprobación. En lugar de en el objeto del servidor, así:

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

Puede ir en el objeto de nivel superior. Básicamente, simplemente sáquelo del objeto del servidor y colóquelo en el objeto de opciones como este:

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

"La topología fue destruida" podría ser causada por la desconexión de la mangosta antes de que se creen los índices de documentos de mongo, según este comentario

Para asegurarse de que todos los modelos tengan sus índices construidos antes de desconectarse, puede:

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

await mongoose.disconnect();
golfadas
fuente
gracias, si está ejecutando casos de prueba, esta es probablemente una respuesta muy probable ...
Nick H247
1
Esto fue para mí. ¡Gracias! Estaba ejecutando pruebas en Jest con mongodb-memory-server, obteniendo errores esporádicos en la topología o manejadores abiertos / Promesas sin terminar. Pero a veces funcionó. Agregar una espera en los índices lo arregló.
roblingle
Recibo este error sin Mongoose, mientras depuro el código Jest como @roblingle y no soy lo suficientemente rápido para pasar por alto las declaraciones. No estoy seguro de qué lo causa, pero establecer puntos de interrupción justo después de las consultas de mongo lo evita.
Dan Dascalescu
@roblingle, ¿cómo terminaste arreglándolo? Acabo de encontrarme con este problema y me hizo imposible conectarme nuevamente a MongoDB. Desde entonces he eliminado todo y reinstalado MongoDB (a través de homebrew) y ahora ya no se ejecutará en el inicio. (Puede ser un problema no relacionado)
bobbyz
Suena no relacionado. Mi aplicación funcionó bien pero las pruebas fallaron.
roblingle
3

El comentario de Sebastian sobre la respuesta de Adrien necesita más atención, me ayudó, pero al ser un comentario podría ser ignorado en algún momento, así que aquí hay una solución :

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);
    }
});
Mamba negro
fuente
2

También tuve el mismo error. Finalmente, descubrí que tengo algún error en mi código. Uso el equilibrio de carga para dos servidores nodejs, pero acabo de actualizar el código de un servidor.

Cambio mi servidor mongod from standalone to replication, pero me olvido de hacer la actualización correspondiente para la cadena de conexión, así que me encontré con este error.

cadena de conexión independiente: mongodb://server-1:27017/mydb cadena de conexión de replicación: mongodb://server-1:27017,server-2:27017,server-3:27017/mydb?replicaSet=myReplSet

detalles aquí :[mongo doc para la cadena de conexión]

lutaoact
fuente
2

Lo conocí en kubernetes / minikube + nodejs + mongoose. El problema era que el servicio DNS estaba funcionando con una especie de latencia. Verificar DNS está listo resolvió mi problema.

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

(los números en db_options se encuentran arbitrariamente en stackoverflow y sitios similares)

tkrizsa
fuente
2

Aquí lo que hice, funciona bien. El problema desapareció después de agregar las siguientes opciones.

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
fuente
2

Debe reiniciar mongo para resolver el error de topología, luego simplemente cambie algunas opciones de mongoose o mongoclient para superar este problema:

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

mongoose.connect(mongoDevString,mongoOptions);
Ganesh Sharma
fuente
Bienvenido a SO! Edite su respuesta y agregue más información, es decir, cómo resuelve el problema, para obtener más orientación, consulte stackoverflow.com/help/how-to-ask
B
1

Recibí este error, mientras creaba una nueva base de datos en mi Comunidad MongoDb Compass. El problema era con mi Mongod, no se estaba ejecutando. Entonces, como una solución, tuve que ejecutar el comando Mongod como precedente.

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

Pude crear una base de datos después de ejecutar ese comando.

Espero eso ayude.

Sibeesh Venu
fuente
1

Estuve luchando con esto durante algún tiempo. Como puede ver en otras respuestas, el problema puede ser muy diferente.

La forma más fácil de averiguar qué está causando es activar loggerLevel: 'info'las opciones

orepor
fuente
0

En mi caso, este error fue causado por una instancia de servidor idéntica que ya ejecutaba en segundo plano.

Lo extraño es que cuando inicié mi servidor sin previo aviso, ya hay uno funcionando, la consola no mostró nada como 'algo está usando el puerto xxx'. Incluso podría subir algo al servidor. Entonces, me llevó bastante tiempo localizar este problema.

Además, después de cerrar todas las aplicaciones que puedo imaginar, todavía no pude encontrar el proceso que utiliza este puerto en el monitor de actividad de mi Mac. Tengo que usar lsofpara rastrear. El culpable no fue sorprendente: es un proceso de nodo. Sin embargo, con el PID que se muestra en el terminal, descubrí que el número de puerto en el monitor es diferente del que usa mi servidor.

Con todo, matar todos los procesos de nodo puede resolver este problema directamente.

AnLuoRidge
fuente
-3

Resolví este problema de la siguiente manera:

  1. asegurando que mongo esté funcionando
  2. reiniciando mi servidor
maia
fuente
44
Esto no evita que el problema vuelva a ocurrir
Sam Munroe,