2012-10-06 10 views
7

Testowałem oficjalnego sterownika MongoDB C# z zestawem replik 3 wystąpień. Stworzyłem prostą aplikację, która uzyskuje dostęp do zestawu replik w pętli.Czy istnieje sposób automatycznego uczynienia sterownika MongoDB C#, aby nie powodował wyjątku EndOfStreamException w przypadku awarii głównego serwera?

Moje pytanie brzmi: Czy możliwe jest, aby sterownik C# ponownie uruchamiał zapytanie automatycznie po zamknięciu serwera głównego, bez rzucania wyjątku EndOfStreamException, tak jak teraz?

Oto mój kod inicjalizacji dla 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)} 

     }; 

A oto kod gdzie kwerendy serwera:

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

Gdybym zamknięcia serwera podstawowego, klient rzuca następujący wyjątek :

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:   

Jeśli po prostu przełknę ten wyjątek i będę kontynuował e pętla, wszystko działa. Dzięki temu może rozwiązać problem i przejść na inny serwer. Ale byłoby wspaniale, gdyby kierowca mógł automatycznie obsłużyć to tak, że w żadnym momencie nie zgłasza wyjątku. Czy to możliwe?

+0

ciche przełączanie serwerów wydaje mi się wątpliwą cechą. Nie wiem, ale wątpię, czy mieliby go lub, że ktokolwiek powinien go używać, ponieważ nie jest dla kierowcy jasne, co powinno oznaczać konsekwencje utraty połączenia z serwerem. – madmik3

+3

Punkt z zestawami replik MongoDB to (między innymi), że możesz mieć automatyczne przełączanie awaryjne w przypadku awarii serwera, awarii sieci itp. Posiadanie sterownika radzi sobie z tym scenariuszem, więc ma to sens! – mookid8000

Odpowiedz

7

W wielu przypadkach niemożliwe byłoby awarie, ponieważ kursor, który jest uruchomiony, istnieje tylko na serwerze głównym. Partie wtórne nic o tym nie wiedzą i dlatego nie mogły kontynuować.

W twoim przypadku zdajesz sobie sprawę, że chcesz kontynuować, ale to zarozumiały z nas, aby wziąć swoje potrzeby i zastosować je we wszystkich sytuacjach. Gdzie chcesz kontynuować pętlę, inni nie.

Poza tym punktem niektóre sterowniki ponawiają próby. Sterownik .NET nie działa, ponieważ uważamy, że nie zawsze możemy ustalić poprawne zachowanie, a zatem pozostawić to aplikacji do podjęcia decyzji.

W przypadku PrimaryPreferred istnieje powód, dla którego chcesz, aby odczyty pochodziły od Primary - ponieważ są aktualne. Jeśli po cichu wrócimy do drugiej strony, to w zależności od tego, jak daleko sięga druga strona, istnieje prawdopodobieństwo, że zapytanie faktycznie zwróci wyniki sprzed ostatniego pomyślnego zapytania do podstawowego. Nie jest to dobre doświadczenie, dlatego po prostu tego nie robimy i zalecamy złapanie tych błędów i samodzielne radzenie sobie z tymi problemami.

Staramy się, aby niektóre z tych błędów zostały zawinięte w wyjątki specyficzne dla MongoDB, aby nie musieć odgadnąć na przykład wyjątku EndOfStream (https://jira.mongodb.org/browse/CSHARP-474). Dodatkowo, jeśli chcesz zobaczyć tę funkcję, zgłoś jirę i zobaczymy, jak możemy to zrobić w przewidywalny sposób - być może używając strategii dostarczonej przez użytkownika do obsługi prób (IRetryStrategy lub coś podobnego).