C# driver 2.0, SocketTimeout, ConnectionTimeout

2,434 views
Skip to first unread message

Dmitriy Krasnikov

unread,
Apr 6, 2015, 11:42:25 AM4/6/15
to mongod...@googlegroups.com
I am not quite clear how to phrase the problem, that I am trying to solve. It boils down to finding if the server is up or not. But as a multiple way of addressing it.
I tried to run:

var setting = new MongoClientSettings
           
{
               
Server = new MongoServerAddress("mongodb://localhost:27017"),ConnectTimeout = TimeSpan.FromSeconds(1),SocketTimeout = TimeSpan.FromSeconds(1)
           
};
var clTest = new MongoClient(setting);
var test = await clTest.ListDatabasesAsync();



Now it happily ignored my timeouts and defaulted to 30 seconds, System.Net.Sockets timeout. I checked the driver code. And at brief glance I can only see the setters for this values. Is it a bug in the driver or am I wrong in assuming Socket timeout in MongoClentSetting should correspond to SocketTimeout in System.Net?

I am getting mighty confused considering how Cluster.DescriptionChanged is also throws away heartbeat exception message.

Please help.

Craig Wilson

unread,
Apr 6, 2015, 12:36:11 PM4/6/15
to mongod...@googlegroups.com
Hi Dmitriy,

The socket timeout gets translated into lower level read and write timeouts (https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Driver/ClusterRegistry.cs#L141
). These are are set here: https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Driver.Core/Core/Connections/TcpStreamFactory.cs#L68.  Same with Connect timeout.  However, what makes this unnecessary is Read and Write timeouts don't apply to asynchronous sockets, which is probably why you don't see these being used. In retrospect, getting rid of these should probably have happened.

However, the easiest way of figuring out if you are connected would be to get the Cluster.Description and iterate over the Servers property and see if each is disconnected or not? Each server description contains the heartbeat exception that was last encountered.

Let me know if this isn't what you are looking for.
Craig

Dmitriy Krasnikov

unread,
Apr 6, 2015, 1:22:38 PM4/6/15
to mongod...@googlegroups.com
Unfortunately it doesn't work for the following reason.
1. The client.Cluster.Description.Servers are only populated AFTER the data calls to MongoDb, i.e.
            var clTest = new MongoClient("mongodb://localhost:27017");
           
var s = clTest.Cluster.Description.Servers; //S=0

           
var test = await clTest.ListDatabasesAsync();

            s
= clTest.Cluster.Description.Servers;//S=1
And that call is the one generating "aggregate" exception due to timeout in System.Net which is 30 seconds.

Craig Wilson

unread,
Apr 6, 2015, 1:50:44 PM4/6/15
to mongod...@googlegroups.com
That's not true. The servers just aren't populated immediately. This is a background task that is running and you are inspecting how the client sees the cluster. In this case, you are just testing before the background task has populated the description with new information.  If you add in a sleep between the ctor and the call to Servers, they would be there (I added a 1 second sleep, for instance). However, just because they are there or not doesn't really mean anything. Servers will show as disconnected unless they are connected. So, if it takes 4 seconds to contact the server, then this will show disconnected for those 4 seconds. If you happen to check before 4 seconds is up, you'll possibly get a bad result. I think you might need to check both the State and that Exception is null.

Perhaps you could provide a description as to what exactly you are attempting to accomplish and perhaps I can help you out that way.

Dmitriy Krasnikov

unread,
Apr 6, 2015, 3:07:42 PM4/6/15
to mongod...@googlegroups.com
Well, I simply want to find out if the server is up, or if the url is correct. Right now the indication, that something is wrong is when the cursor iterate is called and that is a) Generates a generic AggregateException b) The inner exception is Timeout and it is only shows after 30 second timeout.
I tried to call some superfast generic method like list databases to validate if the server is connected, but as I said it takes way too long.

The sad part is that I see all this connection exceptions scrolling in output window, but they are silently handled in the driver. For instance in ClusterableServer.MonitorServer or ClusterableServer.OnDescriptionChanged, I still haven't found why it goes to Timeout exception even when I modify driver code to rethrow, Hopefully next.

But I will appreciate immensely the way to quickly verify connection validity.

P.S I tried to use CancelToken to shorten the wait time, but it wraps the OperationCancelled exception in AggregateException instead. /shrug. Please ignore lazy Exception() throw.

            var clTest = new MongoClient("mongodb://localhost:27017");

           
var cTokenSource = new CancellationTokenSource();
            clTest
.Cluster.DescriptionChanged += (sender, args) =>
           
{
               
var server = args.NewClusterDescription.Servers.FirstOrDefault();
               
if (server==null) throw new Exception("No server connection");
               
if (server.HeartbeatException == null) return;
                cTokenSource
.Cancel();
               
throw server.HeartbeatException;
           
};
           
var s = await clTest.Cluster.SelectServerAsync(new RandomServerSelector(), cTokenSource.Token);

Craig Wilson

unread,
Apr 6, 2015, 3:25:20 PM4/6/15
to mongod...@googlegroups.com
I've filed a ticket here: https://jira.mongodb.org/browse/CSHARP-1231. There is a setting called serverSelectionTimeoutMS which should be exposed via the connection string and MongoClientSettings. However, it currently isn't. I've marked it for 2.0.1. This is the value that is giving you a 30 second timeout, so lowering it to something lower will allow you to timeout faster. 

You can set this, however, through the ClusterConfigurator on MongoClientSettings.

var settings = new MongoClientSettings
{
  ClusterConfigurator = cb => cb.ConfigureCluster(c => c.With(serverSelectionTimeout: TimeSpan.FromSeconds(5)))
};

Also, just to note... Using the driver to check the up-ness of a server is not what these APIs are for. They are optimized and used for the driver to monitor servers and conform to certain specifications all drivers employ. You just happen to be wanting to watch what is going on. That is fine, but if you need something more robust and faster, you might need to use an alternative solution.

Thanks,
Craig

Dmitriy Krasnikov

unread,
Apr 6, 2015, 3:42:15 PM4/6/15
to mongod...@googlegroups.com
Thank you for your help, that was a fastest discussion I ever had about project. You rule.
I don't want to monitor the server. I just wanted not to have exceptions (which relates to cursor also) to show up so late in application. I just wanted to verify the connectivity earlier and give proper exception or logging.
BTW is there way to submit the logger to the driver to record these exceptions? I see the listener object listening to lots of them, but see no way to define and submit mine in my code.

Craig Wilson

unread,
Apr 6, 2015, 3:49:01 PM4/6/15
to mongod...@googlegroups.com
:). The listener API is experimental currently. You can see the (limited) docs here: http://mongodb.github.io/mongo-csharp-driver/2.0/what_is_new/#logging.
Reply all
Reply to author
Forward
0 new messages