We are using the C# driver (1.9.1) for Mongo DB. We have some fallback logic which needs to run if the DB is not accessible, however the default timeout is too long. We tried to change it but the values we put are getting ignored. For the tests we were using the IP of a non-responding machine.
We tried setting the timeout in the connection string:
<add key="Mongo" value="mongodb://xxx.xxx.xxx.xxx:27017/?socketTimeoutMS=2000&connectTimeoutMS=2000&waitqueuetimeoutms=2000"/>
Or via the code:
var client = new MongoClient(new MongoClientSettings
{
Server = new MongoServerAddress("xxx.xxx.xxx.xxx"),
SocketTimeout = new TimeSpan(0, 0, 0, 2),
WaitQueueTimeout = new TimeSpan(0, 0, 0, 2),
ConnectTimeout = new TimeSpan(0, 0, 0, 2)
});
Both time the requests timeout after an average of about 20 seconds.
What could be wrong in the way we are setting the timeout options.
There is a JIRA ticket CSHARP-1018 to track this issue. Basically the driver ignores timeout option when machine is not accessible. Timeout option it is ignored if the machine is turned off or not accessible.
Connection logic has been fixed in 2.0. It currently will try for 30 seconds, but that is configurable to something smaller if you need faster connection times
Please refer to the JIRA ticket to follow progress on this issue.
See the workaround posted to CSHARP-1231 for a way that the ServerSelectionTimeout can be set in the current 2.0.0 version of the driver if you prefer that approach to using shorter timeouts on specific operations.
If you are using the new 2.0 async API you can use a cancellation token to apply your own timeout to the overall operation.
So I would recommend the cancellation token approach in the previous comment. Using short server selection timeouts can result in spurious exceptions during replica set elections if the server selection timeout is shorter than the time it takes an election to complete.
You can write something like this:
var startTime = DateTime.UtcNow;
try
{
using (var timeoutCancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMilliseconds(500)))
{
await collection.Find("{ _id : 1 }").ToListAsync(timeoutCancellationTokenSource.Token);
}
}
catch (OperationCanceledException ex)
{
var endTime = DateTime.UtcNow;
var elapsed = endTime - startTime;
Console.WriteLine("Operation was cancelled after {0} seconds.", elapsed.TotalSeconds);
}
In this example, even though the ServerSelectionTimeout
is still the default value of 30 seconds, this particular operation will be cancelled after only 500 milliseconds (approximately, cancellation can sometimes take slightly longer).
The JIRA ticket referred to by @Robert Stam
mentions a workaround.
I tried it, and it works 100%.
If you are using the new 2.0 async API you can use a cancellation token to apply your own timeout to the overall operation. You can write something like this:
var startTime = DateTime.UtcNow; try { using (var timeoutCancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMilliseconds(500))) { await collection.Find("{ _id : 1 }").ToListAsync(timeoutCancellationTokenSource.Token); } } catch (OperationCanceledException ex) { var endTime = DateTime.UtcNow; var elapsed = endTime - startTime; Console.WriteLine("Operation was cancelled after {0} seconds.", elapsed.TotalSeconds); }
In this example, even though the
ServerSelectionTimeout
is still the default value of 30 seconds, this particular operation will be cancelled after only 500 milliseconds (approximately, cancellation can sometimes take slightly longer).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With