-
Notifications
You must be signed in to change notification settings - Fork 139
MongoServer lifecycle #7
Comments
See MongoClient Connection Pooling. What goes there essentially also goes for MongoRepository since MongoRepository is merely a layer on top of the C# Driver.
|
I'm just instantiating MongoRepository, with a connection string argument. MongoRepository is calling Util's GetDatabaseFromUrl() on my behalf. Callstack is: from where it does this: |
I understand; but why not keep the repository alive (e.g. keep a reference around instead of instantiating a new one every time)? |
Thanks Rob. I did structure things that way for a while. I would prefer to see the dependency on a long lived MongoServer/MongoDatabase object, or a long lived MongoRepository instance made very explicit. The examples need to show that pattern of use - bear in mind many people don't use DI containers, and even if they do, they may inject a MongoRepository instance per request without thinking about it. I managed to figure this out myself, but I know there's a lot of Mongo / .NET noobs who will fall into the trap of simply new'ing up a MongoRepository every time they need it. For your typical business application they may never notice the latency they have incurred. |
I am having trouble reproducing your findings; I have created a very simple test-project that
And we do that in 10 "runs" of 1000 loops: using MongoRepository;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
for (int runs = 0; runs < 10; runs++)
{
var results = new List<TimeSpan>();
for (int i = 0; i < 1000; i++)
{
var s = Stopwatch.StartNew();
var repo = new MongoRepository<Customer>();
repo.Add(new Customer { Name = Guid.NewGuid().ToString("N") });
results.Add(s.Elapsed);
}
Trace.WriteLine(string.Format("Average: {0}", TimeSpan.FromTicks((long)results.Average(r => r.Ticks))));
Trace.WriteLine(string.Format("Total : {0}", TimeSpan.FromTicks((long)results.Sum(r => r.Ticks))));
}
}
}
class Customer : Entity
{
public string Name { get; set; }
}
} My output is:
The above results are for
As you can see it's slower but that is to be expected since we actually have to go through/over the network. The results are pretty similar when in new up the repo outside of the inner for-loop: var repo = new MongoRepository<Customer>();
for (int i = 0; i < 1000; i++)
{
var s = Stopwatch.StartNew();
repo.Add(new Customer { Name = Guid.NewGuid().ToString("N") });
results.Add(s.Elapsed);
} Results:
There's much to say about this test-case (as it doesn't take "warmup" into account, has a abysmal way of measuring etc. etc.) but as you can see my results are very different than from what you are seeing. Are you sure you're not doing very expensive/slow DNS lookups? Or connecting to a high-latency host? Maybe something other network related? |
This is half question, half bug report.
I believe there might be a significant bug in MongoRepository's management of the lifecycle of MongoServer. I believe MongoServer should be singleton/static, and the same instance should be used every time. Otherwise there's some overhead in connecting to the database with each instantiation of the repository.
Here in Util.cs:
private static MongoDatabase GetDatabaseFromUrl(MongoUrl url)
{
var client = new MongoClient(url);
var server = client.GetServer(); // <---- should not be returning a new MongoServer instance!
return server.GetDatabase(url.DatabaseName); // WriteConcern defaulted to Acknowledged
}
See also http://stackoverflow.com/questions/10241641/what-is-the-right-way-to-manage-mongodb-connections-in-asp-net-mvc
I picked this up when looking at performance of queries - was seeing 200ms+ overhead with each new MongoRepository.
Apologies if I have misunderstood the code.
The text was updated successfully, but these errors were encountered: