Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# MongoDB Driver Ignores timeout options

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&amp;connectTimeoutMS=2000&amp;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.

like image 484
DeveloperWithACaffeineProblem Avatar asked Jul 18 '14 12:07

DeveloperWithACaffeineProblem


2 Answers

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).

like image 97
Robert Stam Avatar answered Sep 18 '22 17:09

Robert Stam


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).

like image 28
Contango Avatar answered Sep 17 '22 17:09

Contango