是否有办法自动使MongoDB C#Driver在主服务器出现故障时不抛出EndOfStreamException?

时间:2012-10-06 15:52:24

标签: c# mongodb mongodb-.net-driver

我一直在使用3个实例的副本集测试官方MongoDB C#驱动程序。我创建了一个简单的应用程序,它可以在循环中访问副本集。

我的问题是:当我关闭主服务器时,是否有可能让C#驱动程序自动重新运行查询,而不像现在那样抛出EndOfStreamException?

这是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)}

        };

这是我查询服务器的代码:

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

如果我关闭主服务器,则客户端会抛出以下异常:

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:           

如果我只是吞下这个异常并继续循环,一切正常。所以它可以解决问题并切换到另一台服务器。但是如果驱动程序能够自动处理这个问题会很好,那么它就不会抛出异常。可能吗?

1 个答案:

答案 0 :(得分:7)

在许多情况下,由于正在执行的游标仅存在于主服务器上,因此无法进行故障转移。辅助人员对此一无所知,因此无法继续。

在你的情况下,你知道你想要继续,但是我们很自然地会把你的需要应用到所有情况中。你想继续循环的地方,其他人可能不会。

除此之外,某些驱动程序会重试查询。 .NET驱动程序没有,因为我们觉得我们无法始终确定正确的行为,因此需要由应用程序决定。

对于PrimaryPreferred,有一个原因是您希望读取来自主节点 - 因为它们是最新的。如果我们默默地回退到辅助节点,那么根据辅助节点的返回距离,您的查询有可能实际返回上次成功查询到主节点之前的结果。这不是一个好的体验,因此我们根本不这样做,并建议您自己捕获这些错误并自行处理重试。

我们希望将一些错误包含在MongoDB特定的异常中,这样您就不必猜测EndOfStream异常(https://jira.mongodb.org/browse/CSHARP-474)。此外,如果您希望看到此功能,请提交jira,我们将研究如何以可预测的方式执行此操作 - 可能使用用户提供的策略来处理重试(IRetryStrategy或其他)。