Properly shutting down MongoDB database connection from C# 2.1 driver? - c#

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

Related

Should C# ClientWebSocket be declared static or instance?

I am currently creating a .NET6 C# trading API client application and the API has two different WebSocket endpoints.
I'm wondering whether the ClientWebSocket object (System.Net.WebSockets) should be declared static or instance. I'm aware HttpClient should be declared static to prevent unnecessary new connections so I'm wondering if the same rationale applies to ClientWebSocket.
From my testing so far my impression is that the ClientWebSocket should be connected and disconnected manually as required, opposed to leaving it connected without any requirement (i.e. just pinging and ponging), and therefore instance objects may be fine to use. Put another way: if websocket connections are explicitly managed there does not appear to be an issue of 'connection re-use' like HttpClient and therefore instances are ok.
Having said that, another design option might be to declare the ClientWebSocket as static and just maintain an open connection + auto re-connect as long as the application is running.
My current design is to have two instance objects of ClientWebSocket, one for each API endpoint. They will be newed up each time a connection is needed.
Any thoughts appreciated.

Does mongodb C# driver make server call to get database?

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.

Active connections number reached maximum Mongo Atlas

I have an .NetCore application. My DB is Mongo and hosted on Mongo Atlas. I reach the number of maximum connections very easy. I have a lot of request made to the db but my connection with the DB is Singletone.
I connect to Mongo through Mongo Client
MongoClient client = new MongoClient(config.GetConnectionString("Dbconnectionstring"));
IMongoDatabase database = client.GetDatabase("database");
All this in a class that is registered as a singletone in Startup.cs
services.AddSingleton<MongoUnitOfWork>();
I did not have this problem before. On this current application I have to make a lot of requests to the db but if I registered the connection as I singleton I expected to use the same connection and not open a new one for every request. At least this is what I think it happens.
UPDATE
I used a recurrent service named HangFire (intended to use for recurring jobs) that needed a connection string to the DB. Even though I didn't put any function to be automatically called every 1 minute or something similar, I think this was the problem. For now I commented every thing about this service and everything went back to normal.
I will get back as soon as I'm 100% sure that this was the problem.
UPDATE 2
Today I had the problem again so I figured that the Recurrent Service wasn't the problem.
UPDATE 3
Last time when I got rid of that service I also deleted all the connections. Until now I didn't have another problem and when I checked them in the day that I deleted the service all seemed fine. Today I checked again the connections and I had around 70. Apparently the connections don't close.
Also, yes, I'm sure I'm using a singleton to instantiate the MongoClient. I also put breakpoints to see if the they are hit on request. Not the requests are the problem.

Permanent connection to cassandra or connection per request?

I'm right now implementing my own UserStore for WebApi 2 so it works with cassandra. My question is, if i should close the connection after a request and reconnect to cassandra for the next request.
Right now i am establishing the connection at startup of the application and passing a cassandra Context to the UserStore to work with. the connection is closed when i shut down the application.
I'm wondering if e.g. 10 people register at the same, is this possible with only one connection?
static Startup()
{
PublicClientId = "self";
//Connecting to Cassandra
Cluster cluster = Cluster.Builder().AddContactPoint("127.0.0.1").Build();
Session session = cluster.Connect();
Context context = new Context(session);
//passing context
UserManagerFactory = () => new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
}
//UserStore Method for Registration
public virtual Task CreateAsync(TUser user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
var usertable = _context.GetTable<TUser>("users");
//insert user into table
}
When you are deciding if you should have connection pooling or not, there is typically 2 questions you need to answer:
What is the cost of establishing connection every time?
Establishing connection on some networks like EC2 is more expensive depending on the type of network and machines and your architecture setup. It can take several milliseconds and that adds up to your query time if you are establishing connections every time. If you care about saving those milliseconds, then pooling connections is a better option for you.
Connections to databases are resources managed by your OS that your Application Server and DB server are holding onto while being consumed or sleeping. If your hardware resources are low, the connections should be treated like files. You open them, read from, or write to them, then close them. If you don't have hardware resource constraints then don't worry about pooling resource.
On the Cassandra side if you set your rpc_server_type to sync, then each connection will have its own thread which takes minimum of 180K and if you have a lot of clients, then memory will be your limiting factor. If you chose hsha as rpc_server_type, then this won't be a problem.
Read this: https://github.com/apache/cassandra/blob/trunk/conf/cassandra.yaml#L362
About your application performance:
Ideally if you are using Cassandra with a multi-node setup, you want to distribute your requests to multiple nodes (coordinators) so that it scales better. Because of this it is better if you don't stick with the same connection as you will always be talking to the same co-ordinator.
Secondly, if you are multi-threading, you want to make sure your connection is sticking with the same thread while being used for the duration of each query to Cassandra, otherwise, you may end up with race conditions where one thread is updating resources of the connection which is already being used (e.g. trying to sent query packets to server, when it previously was waiting for a response from server).
I recommend implementing a thread-safe connection pool and open several connections on startup of your application and randomly use them for each of your requests, and kill them when your application server stops. Make sure you consider changing the rpc_server_type in Cassandra if you have hardware constraints.
The DataStax C# driver already provides connection pooling internally, thus the recommended way to use the driver is to use a Cluster instance per your C* cluster and a Session per keyspace.Basically initialize these at the startup of your app (nb you can also prepare the PreparedStatements too), reuse these across request, and close them for cleanup when stopping the app (for upgrading, etc).
I'd strongly recommend you to give a quick read of the C# driver docs. It shouldn't take you long and you'll know more about what's included in the driver.

SQL Exception: "Impersonate Session Security Context" cannot be called in this batch because a simultaneous batch has called it

When opening a connection to SQL Server 2005 from our web app, we occasionally see this error:
"Impersonate Session Security Context" cannot be called in this batch because a simultaneous batch has called it.
We use MARS and connection pooling.
The exception originates from the following piece of code:
protected SqlConnection Open()
{
SqlConnection connection = new SqlConnection();
connection.ConnectionString = m_ConnectionString;
if (connection != null)
{
try
{
connection.Open();
if (m_ExecuteAsUserName != null)
{
string sql = Format("EXECUTE AS LOGIN = {0};", m_ExecuteAsUserName);
ExecuteCommand(connection, sql);
}
}
catch (Exception exception)
{
connection.Close();
connection = null;
}
}
return connection;
}
I found an MS Connect article which suggests that the error is caused when a previous command has not yet terminated before the EXECUTE AS LOGIN command is sent. Yet how can this be if the connection has only just been opened?
Could this be something to do with connection pooling interacting strangely with MARS?
UPDATE: For the short-term we have implemented a workaround by clearing out the connection pool whenever this happens, to get rid of the bad connection, as it otherwise keeps getting handed back to various users. (This now happens a 5-10 times a day with only a small number of simultaneous users, so it is fairly annoying.) But if anyone has any further ideas, we are still looking out for a real solution...
I would say it's MARS rather then pooling
From "Using Multiple Active Result Sets (MARS)"
Applications can have multiple default
result sets open and can interleave
reading from them.
Applications can
execute other statements (for example,
INSERT, UPDATE, DELETE, and stored
procedure calls) while default result
sets are open.
Connection pooling in it's basic form means the connection open/close overhead is minimised, but any connection (until MARS) has one thing going on at any one time. Pooling has been around for some time and just works out of the box.
MARS (I've not used it BTW) introduces overlapping "stuff" going on for any single connection. So it's probably MARS rather than connection pooling is the bigger culprit of the 2.
From "Extending Database Impersonation by Using EXECUTE AS"
When impersonating a principal by
using the EXECUTE AS LOGIN statement,
or within a server-scoped module by
using the EXECUTE AS clause, the scope
of the impersonation is server-wide.
This may explain why MARS is causing it: the same principal in 2 session both running EXECUTE AS.
There may be something in that article of use, or try this:
IF ORIGINAL_LOGIN() = SUSER_SNAME() EXECUTE AS LOGIN = {0};
On reflection and after reading for this answer, I've not convinced that trying to change execution context for each session (MARS) in one connections is a good idea...
Don't blame connection pooling - MARS is quite notorious for wreaking a havoc. It's not entirely it's blame but it's kind of half and half. The key thing to remember is that MARS is designed, and only works with "normal" DB use (meaning, regular CRUD stuff no admin batches). Any commands that have a wide effect on DB engine can trip MARS even if it's just one connection and single threaded (like running a setup batch to create tables or a nested transaction).
Having said that, one can easily just blame MARS, but it works perfecly fine for normal CRUD scenarios which are like 99% (and things with low efficiencey like ORM-s and LINQ depend on it for life). Meaning that it's important for people to learn that if they want to hack SQL through a connection they can't use MARS. For example I had a setup code that was creating whole DB from scratch, beceuse it's very convenient for deployment, but it was sharing connection sting with web service it was deploying - oops :-) Took me a few days of digging to learn my lesson. So I just maintain the separation of concerns (which is always good) and problems went away.
Have you tried to use a revert at the end of your sql statement?
http://msdn.microsoft.com/en-us/library/ms178632.aspx
I always do this to just make sure the current context is back to normal.

Categories

Resources