[CSHARP-1830] A timeout occured selecting a server if executing inside of a task. Created: 17/Nov/16  Updated: 20/Jul/20  Resolved: 20/Jul/20

Status: Closed
Project: C# Driver
Component/s: Connectivity
Affects Version/s: 2.3
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Mikhail Belov Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Dev env: Windows 10 x64, MongoDB 3.2.4 as Windows Service;
Prod env: Windows Server 2012 R3 x64, MongoDB hosted by Ubuntu VM



 Description   

Hi, I'm trying to use MongoDB in my project but faced with the following problem. I have some amount of tasks. Simple Find() operation inside of a task throws "A timeout occured after 30000ms selecting a server using CompositeServerSelector ...".

I write a small console app to catch the error. I have MongoDB instance hosted locally by my Windows dev machine. The database is really small (1 collection, 21 objects, 95 bytes average). It means network or size could not be the reason. Moreover I found out the following:

  • If I run the Find() method 40 one after another (no tasks) - it takes less than a second to finish.
  • If I run just a few tasks simultaneously (like 5) - it takes a few seconds to finish
  • But if I run 40 tasks simultaneously without using async-await pattern - some of them end up with timeout exception, some of them return the data. Average task exection time is 18 seconds.
  • If I run 40 tasks and use async-await pattern it works a little bit slowly then continuous execution and do not throw timeout exception.

The following code throws the timeout exception:

static void Main() {
    int iterations = 40;
    var tasks = new Task<TimeSpan>[iterations];
    for (int i = 0; i < iterations; i++) {
        var tempI = i;
        tasks[i] = new Task<TimeSpan>(() => {
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            var integrationId = INTEGRATION_IDS[i];
            try {
                var metadataCollection = database.GetCollection<CacheMetadata>(METADATA_COLLECTION_NAME);
                CacheMetadata metadata = metadataCollection
                    .Find(m => m.IntegrationId == integrationId)
                    .FirstOrDefault(); // If FirstOrDefaultAsync().Result is used it throws the exception as well
                stopwatch.Stop();
                // Write metadata to console
            }
            catch (Exception ex) {
                // Write exception to console
            }
            return stopwatch.Elapsed;
        });
    }
    for (int i = 0; i < iterations; i++) {
        tasks[i].Start();
    }
    Task.WaitAll(tasks);
}

However the following code works:

static void Main() {
    int iterations = 40;
    var tasks = new Task<TimeSpan>[iterations];
    for (int i = 0; i < iterations; i++) {
        var integrationId = INTEGRATION_IDS[tempI];
        tasks[i] = runMongoQuery(integrationId);
    }
    Task.WaitAll(tasks);
}
private static async Task<TimeSpan> runMongoQuery(Guid _integrationId) {
   var stopwatch = new Stopwatch();
   stopwatch.Start();
   try {
       var metadataCollection = database.GetCollection<CacheMetadata>(METADATA_COLLECTION_NAME);
       CacheMetadata metadata = await metadataCollection
           .Find(m => m.IntegrationId == _integrationId)
           .FirstOrDefaultAsync();
       stopwatch.Stop();
       // Write metadata to console
   }
   catch (Exception ex) {
       // Write exception to console
   }
   return stopwatch.Elapsed;
}

Is it a bug or I'm doing something wrong?

Thanks.



 Comments   
Comment by Jeffrey Yemin [ 20/Jul/20 ]

mbelov sorry for losing track of this. I'm inclined to close it now, given the comments above. If you disagree, we can re-open.

Comment by Frank Zheng [ 08/Aug/18 ]

Hi Mikhail,

Please check my answer here:

https://stackoverflow.com/questions/38859755/system-timeoutexception-a-timeout-occured-after-30000ms-selecting-a-server-usin/51281357#51281357

In your example, you can simply turn the "new Task(action)" into "new Task(action, TaskCreationOptions.LongRunning);".

However, this is not the ultimate solution. In the real world, this Main function might actually be called by a timer, or an arbitrary thread. In this case, it will failed with such a simply fix.

You need to follow my practice in the link provided if you still encounter the problem.

{{Thanks,
Frank}}

 

Comment by Mikhail Belov [ 17/Nov/16 ]

One more thing. I found out that if I do some query in a moment when I create database connection in order to open it (probably there is a way to do it without fake query) and left the rest code the same, it works as expected without any timeout exceptions. Looks like the problem is that the driver cannot open the connection executing inside of a task while if there are number of tasks are working in the same time.

Comment by Mikhail Belov [ 17/Nov/16 ]

Just found out that pure threads instead of tasks work just fine.

Generated at Wed Feb 07 21:40:47 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.