When should I call MongoClient.GetServer() and MongoServer.GetDatabase()?
Previously I was creating a single MongoDatabase instance at startup and using that for all operations. The problem is that when failover occurs, the primary becomes a different node, making the instance incorrect.
Should I call myClient.GetServer().GetDatabase(myDatabaseName) for every operation? This is probably the most correct, although some calls will fail during failover anyway. I'm tempted to reuse the same database instance for at least a group of operations.
My main concern is that calling GetServer() and GetDatabase() frequently will introduce overhead. I'm sure the driver will use the connection pool and hope that it will do caching of instances, but I do not know when it will have to talk to the server.
You should have one MongoClient representing your abstract connection to the database, one GetServer() call to instantiate a MongoServer instance with a given set of options, and one GetDatabase() call to instantiate a MongoDatabase instance. For the same set of options, you shouldn't need multiple instance of these objects.
It seems like the root cause of this question is failover hndling. The driver should discover the whole replica set and connect to the primary automatically. When failover occurs, there's a period where there is no primary as the election happens, but then the driver should connect to the new primary and resume normal operation. Your client code should be able to handle the failover period, in whatever way is appropriate for your application. The failover won't invalidate your MongoClient, MongoServer, or MongoDatabase instances.
Related
I am using mongodb c# driver v2.7.3.
I would like to know if client.GetDatabase() statement makes a call to mongodb server or not?
IMongoClient client = this.dbConnection.client;
var db = client.GetDatabase(databaseName);
Does it internally goes to the mongod shell and run use db command ?
I have many concurrent requests to get the instance of IMongoDatabase. If the driver is making a server call then it would be good if I cache the instance to improve performance.
Looking at the source code, it does not seem that it is making a server call.
But how can I confirm ?
Mongo Db Source Gitlab
If you refer to the Mongo C# Driver references, you'll see a couple of notes.
MongoClient Re-Use
It is recommended to store a MongoClient instance in a global place, either as a static variable or in an IoC container with a singleton lifetime.
However, multiple MongoClient instances created with the same settings will utilize the same connection pools underneath. Unfortunately, certain types of settings are not able to be compared for equality. For instance, the ClusterConfigurator property is a delegate and only its address is known for comparison. If you wish to construct multiple MongoClients, ensure that your delegates are all using the same address if the intent is to share connection pools.
IMongoDatabase Re-use
The implementation of IMongoDatabase provided by a MongoClient is thread-safe and is safe to be stored globally or in an IoC container.
For more info about storing instances and other use cases, you can look at http://mongodb.github.io/mongo-csharp-driver/2.9/reference/driver/connecting/
Until you interact with the MongoClient or the IMongoDatabase instance the connection is not actually established or validated. If you will be using a singleton to store your client instance a test similar to the following could be used:
try
{
_client = new MongoClient(settings);
_database = _client.GetDatabase(db.DatabaseName);
_database.RunCommand((Command<BsonDocument>)"{ping:1}");
}
catch
{
// there is a problem with the settings do not store
}
The above sends a ping command which can be used to test if the server is responding to commands. It will also force the connection to be established via the MongoClient and ensure the connection is valid as a result.
I am just getting started with integrating MongoDB into my application and I have ran into a few questions. In my application I am using the newest 2.1 version of the MongoDB C# driver and only using MongoDB for application logging.
Currently before showing my main application Form I first check to see if mongod.exe is running and if not I start it. Then when my main Form is shown it opens a connection to the database for use seen below.
public void Open()
{
Client = new MongoClient("mongodb://localhost:27017");
Database = Client.GetDatabase(DBName);
Collection = Database.GetCollection<BsonDocument>(ColName);
}
My question is how I should properly shutdown this connection when my application is closing?
Also are there in considerations I should take into account in leaving mongod.exe running versus exiting it each time the application closes?
I have searched a few times trying to figure out if there is a proper way to shutdown the connection but have found nothing very specific. There is an old SO post (that I can't seem to find now) mentioning a .Dispose method, though I cannot seem to find it in the newest driver nor from my IDE's auto complete.
As of today's version of MongoDB (v2.0.1.27 for MongoDB.Driver), there's no need to close or dispose of connections. The client handles it automatically.
From the docs:
A MongoClient object will be the root object. It is thread-safe and is all that is needed to handle connecting to servers, monitoring servers, and performing operations against those servers.
[...]
It is recommended to store a MongoClient instance in a global place, either as a static variable or in an IoC container with a singleton lifetime. However, multiple MongoClient instances created with the same settings will utilize the same connection pools underneath.
There's a partial/old list of thread-safe MongoDB classes in this SO answer.
The question seems to have been already kinda asked here at When should i be opening and closing MongoDB connections?
If it's accepted answer,
I would leave the connection open as re-creating the connection is
costly. Mongo is fine with lots of connections, open for a long time.
What you ideally should do is to share the connection with all parts
of your application as a persistent connection. The C# driver should
be clever enough to do this itself, so that it does not create too
many connections, as internally it uses "connection pooling" that
makes it even re-use connections. The docs say: "The connections to
the server are handled automatically behind the scenes (a connection
pool is used to increase efficiency)."
works fine for you then all well and good. Even the MongoDB C# driver's quick tour page lends the same advice -
Typically you only create one MongoClient instance for a given cluster
and use it across your application. Creating multiple MongoClients
will, however, still share the same pool of connections if and only if
the connection strings are identical.
Otherwise, I think you can simply put your call to create the connection in a using(){} code block. It automatically calls the dispose method for you (as it implements the IDisposable pattern). You should use this block for any resource you want disposed.
From my experience, the correct way is as answered, but even following these recommendations, I still was having random EndOfStreamException. It seems that some problems are caused by the internet provider closing the connection after some time.
I Solved it by adding:
MongoClientSettings settings = MongoClientSettings.FromUrl(new MongoUrl(connectionString));
settings.SslSettings = new SslSettings() { EnabledSslProtocols = SslProtocols.Tls12 };
settings.MaxConnectionIdleTime = TimeSpan.FromSeconds(30);
I have a few DbContextes that connects to the same database in the same application.
I noticed that EF6 has a new constructor: https://msdn.microsoft.com/en-us/library/gg696604(v=vs.113).aspx
My question is then, lets say I hook up my DI framework to create a SqlConnection for each request and passes this to each of the DbContexts with this new constructor instead, would that be the correct way to go about it? Or should the Sql connection be longlived and not per request?
public async Task<SqlConnection> GetOpenedConnectionAsync()
{
_connection = new SqlConnection(_config.AscendDataBaseConnectionString);
await _connection.OpenAsync(_cancel.Token);
return _connection;
}
Register above per application lifetime or per request lifetime?
Depends on your use case but in general i would highly discourage Singleton scope.
Generally the cost of creating a new connection and tearing it down is low, unless there is a long packet delay between Server and Db (e.g. mobile) but if servers are close this is < 5ms.
If lets say you have 1 database, used by a thousand servers (load balancing or whatever), if all those servers always kept an open connection you may run into issues, but if you had each one open and close connections as and when needed, this probably would work.
If you have 1 database, and 1 or 2 servers, you could have a single connection (to save a small amount of time per request) but there are pitfalls and i would HIGHLY discourage it because:
If you open a transaction, no other query will be able to run until that transaction finishes as there can only be 1 transaction at any time per connection. E.g. User A tries to list all Customers (takes 5 seconds), this means no other query can run until you get all the customers back.
If a transactions gets opened, and for whatever reason it does not commit, you will basically loos complete connectivity to the database until that transaction gets rolled back/committed, which may or may not happen.
What is the best practice for managing the MongoServer class life cycle? Should I create one and close it at the end of each request or should it be kept as a singleton for the entire life of the app using something like StructureMap?
Any help is appreciate.
In the official documentation it is stated that MongoServer, MongoDatabase, and MongoCollection are thread safe, and that you're supposed to create one single MongoServer for each database that you connect to.
Thus, MongoServer, MongoDatabase, and MongoCollection can safely be configured to be singletons. MongoServer will even help enforcing this by returning the same MongoDatabase instance for successive calls, and MongoDatabase will do the same thing for MongoCollections.
I.e. your MongoServer instance can safely be configured to have a singleton lifestyle in your IoC container, and you might as well set up injection for MongoDatabase and maybe even MongoCollection as well.
I'm using this strategy with Windsor myself - you can see my MongoInstaller here: https://gist.github.com/2427676 - it allows my classes to just go ahead and do this:
public class SomeClass
{
public SomeClass(MongoCollection<Person> people)
{ ... }
}
in order to have a collection injected, nice and ready to use.
The C# driver manages connections to the server automatically (it uses a connection pool). There is no need to call server.Connect as the driver connects automatically. Don't call server.Disconnect as that closes all connections in the connection pool and interferes with efficient connection pooling.
As far as managing the lifecycle of the MongoServer instance you are free to store it in a static variable and use it for the lifetime of your process (and share it across threads, it is thread-safe). Alternatively, you can just call MongoServer.Create again whenever you need to get the server instance. As long as you keep calling MongoServer.Create with the same connection string you will keep getting back the same MongoServer instance.
Inject it using any IOC container (structuremap, Windsor etc.) and keep its lifetime to be on per request basis.
Basically what I do now is:
During initialization
create connection and store it
create DbDataAdapters and their commands with the stored connection
call DbDataAdapter.Fill for each
adapter to populate DataTables from database
and when handling requests
insert/update/delete rows in DataTables
call DbDataAdapter.Update at some point. Not necessarily every time (update uses naturally adapter's commands' connection)
Is this the correct way or should I always create a new connection when request arrives, and then assign it to DbDataAdapter.Insert/Update/DeleteCommand.Connection, before calling DbDataAdapter.Update? I'm thinking about issues like reconnecting to db after network/server problem.
Thanks & BR -Matti
Because you mention web services, think about concurrency. What if two or more concurrent requests are processed at your server side.
Is it ok to use the same connection? Is it ok to use the same DataAdapter?
The most probable answer is - it's not, it probably would not work.
Thus, the safest approach is to create a new connection and a new data adapter upon each request.
Since connections are pooled, there should be no issues with "reconnecting" - the pool serves a connection and the handshake was probably performed before. There's then no performance hit.