2012-10-06 7 views
7

He estado probando el controlador oficial MongoDB C# con un conjunto de réplicas de 3 instancias. Creé una aplicación simple que accede al conjunto de réplicas en un bucle.¿Hay alguna manera de hacer que el controlador MongoDB C# automáticamente no genere una excepción EndOfStreamException cuando el servidor primario se apaga?

Mi pregunta es: ¿es posible hacer que el controlador C# vuelva a ejecutar la consulta automáticamente cuando cierro el servidor primario, sin que arroje la EndOfStreamException como lo hace ahora?

Aquí está mi código de inicialización para los MongoServerSettings:

 var settings = new MongoServerSettings() 
     { 
      ConnectionMode = ConnectionMode.ReplicaSet, 
      ReplicaSetName = "mongors", 
      ReadPreference = new ReadPreference(ReadPreferenceMode.PrimaryPreferred), 
      SafeMode = SafeMode.True, 
      DefaultCredentials = new MongoCredentials("user", "password"), 
      Servers = new[] { new MongoServerAddress("server.net", 27020), 
         new MongoServerAddress("server.net", 27019), 
         new MongoServerAddress("server.net", 27018)} 

     }; 

Y aquí está el código en el que consultar al servidor:

 while (true) 
     { 
      var server = MongoServer.Create(settings); 
      var db = server.GetDatabase("db"); 
      var collection = db.GetCollection<TaggedAction>("actions"); 
      var query = Query.EQ("_id", id); 
      var entity = collection.FindOne(query); 

      Console.WriteLine(DateTime.Now +" " + entity.ActionName); 

      Thread.Sleep(2500); 
     } 

Si apago el servidor principal, el cliente lanza la siguiente excepción :

System.IO.EndOfStreamException was unhandled 
    HResult=-2147024858 
    Message=Attempted to read past the end of the stream. 
    Source=MongoDB.Bson 
    StackTrace: 
     at MongoDB.Bson.IO.BsonBuffer.LoadFrom(Stream stream, Int32 count) in C:\work\rstam\mongo-csharp-driver\Bson\IO\BsonBuffer.cs: line 314 
     at MongoDB.Bson.IO.BsonBuffer.LoadFrom(Stream stream) in C:\work\rstam\mongo-csharp-driver\Bson\IO\BsonBuffer.cs: line 281 
     at MongoDB.Driver.Internal.MongoConnection.ReceiveMessage(BsonBinaryReaderSettings readerSettings, IBsonSerializationOptions serializationOptions) in C:\work\rstam\mongo-csharp-driver\Driver\Internal\MongoConnection.cs: line 478 
     at MongoDB.Driver.MongoCursorEnumerator`1.GetReply(MongoConnection connection, MongoRequestMessage message) in C:\work\rstam\mongo-csharp-driver\Driver\Core\MongoCursorEnumerator.cs: line 296 
     at MongoDB.Driver.MongoCursorEnumerator`1.GetFirst() in C:\work\rstam\mongo-csharp-driver\Driver\Core\MongoCursorEnumerator.cs: line 253 
     at MongoDB.Driver.MongoCursorEnumerator`1.MoveNext() in C:\work\rstam\mongo-csharp-driver\Driver\Core\MongoCursorEnumerator.cs: line 141 
     at System.Linq.Enumerable.FirstOrDefault(IEnumerable`1 source) 
     at MongoDB.Driver.MongoCollection.FindOneAs(IMongoQuery query) in C:\work\rstam\mongo-csharp-driver\Driver\Core\MongoCollection.cs: line 557 
     at MongoDB.Driver.MongoCollection`1.FindOne(IMongoQuery query) in C:\work\rstam\mongo-csharp-driver\Driver\Core\MongoCollection.cs: line 1734 
     at ConsoleApplication16.Program.Main(String[] args) in Program.cs: line 53 
     at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
     at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
     at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
     at System.Threading.ThreadHelper.ThreadStart() 
    InnerException:   

Si me trago esta excepción y continúo con th e loop, todo funciona. Por lo tanto, puede resolver el problema y cambiar a otro servidor. Pero sería genial si el controlador pudiera manejar esto automáticamente, de modo que en ningún punto arroje la excepción. ¿Es posible?

+0

cambiar silenciosamente los servidores parece ser una característica cuestionable para mí. No sé, pero dudo que lo tengan o que alguien debería usarlo, ya que no está claro para el conductor cuáles deberían ser las implicaciones de perder una conexión de servidor. – madmik3

+3

El punto de los conjuntos de réplicas de MongoDB es (entre otras cosas) que puede tener conmutación por error automática en caso de fallas del servidor, cortes de red, etc. ¡Tener el controlador para manejar este escenario tendría tanto sentido! – mookid8000

Respuesta

7

En muchos casos, sería imposible realizar una conmutación por error porque el cursor que se está ejecutando solo existe en el servidor primario. Los secundarios no saben nada al respecto y, por lo tanto, no podrían continuarlo.

En su caso, usted sabe que desea continuar, pero sería presuntuoso de nosotros tomar sus necesidades y aplicarlas a todas las situaciones. Donde quiera simplemente continuar el ciclo, otros no.

Aparte de ese punto, algunos controladores reintentan las consultas. El controlador .NET no funciona porque creemos que no siempre podemos determinar el comportamiento correcto y, por lo tanto, dejarlo a la aplicación para decidir.

En el caso de PrimaryPreferred, hay una razón por la que desea que las lecturas provengan de la Primaria, ya que están actualizadas. Si silenciosamente volvemos a la secundaria, entonces, dependiendo de qué tan atrás esté la secundaria, existe la posibilidad de que su consulta realmente devuelva los resultados antes de la última consulta exitosa a la primaria. Esta no es una buena experiencia y, por lo tanto, simplemente no lo hacemos y recomendamos que detecte estos errores y maneje los reintentos usted mismo.

Estamos buscando algunos de estos errores envueltos en excepciones específicas de MongoDB para que no tenga que adivinar cosas como una excepción EndOfStream (https://jira.mongodb.org/browse/CSHARP-474). Además, si desea ver esta característica, presente una jira y veremos cómo podemos hacer esto de manera predecible, tal vez utilizando una estrategia suministrada por el usuario para manejar los reintentos (IRetryStrategy o algo así).

Cuestiones relacionadas