Getting timeout expired. Timeout period elapsed prior to obtaining connection from connection pool with Dapper - dapper

One application is giving exception timeout period elapsed prior to obtaining connection from connection pool. I have used below code, this code snippet is called from different concurrent users and can have maximum hits up to 10000 pr.second. I have used Dapper for fetching the results from Azure MS SQL database.
public async Task<List<Results>> GetDBResults(string Id, int skip, int take)
{
var values = new DynamicParameters();
values.Add("Id", Id);
values.Add("Skip", skip);
values.Add("Take", take);
using var connection = GetConnection(AppSettingsProvider.TryGet("ConnectionString"));
try
{
var sw = Stopwatch.StartNew();
//connection.Open();
// QueryAsync is from Dapper
var dbResult = await connection.QueryAsync<ResponseObject>("SP_name", param: values,
commandType: CommandType.StoredProcedure, commandTimeout: Constants.CommandTimeout);
var result= dbResult?.ToList();
Console.WriteLine("execution time = {0} seconds\n", sw.Elapsed.TotalSeconds);
return result;
}
finally
{
connection.Close();
}
}
private SqlConnection GetConnection(string connectionString)
{
var sqlConnection = new SqlConnection(connectionString);
return sqlConnection;
}
I know, 'using' will close and dispose the connection object, Connection is getting closed but DB pool is not available immediately to next DB connection. So, I have closed DB connection explicitly in final block. This made me to execute few more concurrent request successfully. After that, I am getting timeout exception.
Connection.Open is managed by Dapper, so no connection.Open is added to the code snippet.
We are getting timeout issue after concurrent users crossing more than 200 hits.
Please let me know the resolution to this problem.

This would appear to be a pool exhaustion issue; if you have 10000 requests per second, and noting that the default connection pool size is 100, then even if everything else works perfectly (never CPU starvation, GC stalls, etc), then you only have 10ms for your "acquire, execute, release" loop (since each of the 100 connections needs to handle 100 requests per second to achieve a total of 10k/s requests). That's pretty ambitious, to be honest, even on hardware with a good LAN - if you're in the cloud ("Azure MS SQL"): forget it (unless you're paying for very very high tier services). You could try increasing the pool size, but I honestly wonder whether some kind of redesign is the way to look here. The fact that you're measuring the time in seconds emphasizes the scale of the problem here:
Console.WriteLine("execution time = {0} seconds\n", sw.Elapsed.TotalSeconds);

Related

sp_getapplock in service using ormlite - always returns 0 - Unable to implement distributed lock

I'm executing a method that I only want to execute one time to avoid some race conditions. Unfortunately, the sp_getapplock always returns 0 in that it retrieved the lock.
public void Any(MenuScheduleUpdateLocationRequest req)
{
using (var trans = Db.OpenTransaction()) {
var hasLock = Db.SqlScalar<int>($"exec sp_getapplock #Resource='location-{req.LocationId}',#LockMode='Exclusive',#LockOwner='Transaction',#LockTimeout=0");
if (hasLock!=0) {
// should mean someone else has a lock and we just should abort
return;
}
// the rest of the code
trans.commit(); // releases the lock
}
The pasted code above always returns 0. I've tested this by creating several hangfire jobs and having them execute this code at the same time. The method takes about a minute to run and creates duplicate records which wouldn't happen if the lock worked.
Service Stack Service using ORMLite's IDBConnectionFactory standard registration in the app host:
var factory = new OrmLiteConnectionFactory(ConfigUtils.GetConnectionString("umbracoDbDSN"),
SqlServer2017Dialect.Provider);
container.Register<IDbConnectionFactory>(factory);
SQL Azure database, azure app service (windows).
I don't really know if this is an ormlite issue, SQL provider, or a misunderstanding on my part.

Go MongoDB (mgo) - doesn't release closed connections

My MongoDB database has a fast-growing amount of active connections.
I wrote a code to test how connection creation/closing flow works. This code sums up how I use the mgo library in my project.
package main
import (
"time"
"fmt"
"gopkg.in/mgo.v2"
)
func main() {
// No connections
// db.serverStatus().connections.current = 6
mongoSession := connectMGO("localhost", "27017", "admin")
// 1 new connection created
//db.serverStatus().connections.current = 7
produceDataMGO(mongoSession)
produceDataMGO(mongoSession)
produceDataMGO(mongoSession)
produceDataMGO(mongoSession)
// 4 new connections created and closed
// db.serverStatus().connections.current = 7
go produceDataMGO(mongoSession)
go produceDataMGO(mongoSession)
go produceDataMGO(mongoSession)
go produceDataMGO(mongoSession)
// 4 new connections created and closed concurrently
// db.serverStatus().connections.current = 10
time.Sleep(time.Hour * 24) // wait any amount of time
// db.serverStatus().connections.current = 10
}
func connectMGO(host, port, dbName string) *mgo.Session {
session, _ := mgo.DialWithInfo(&mgo.DialInfo{
Addrs: []string{fmt.Sprintf("%s:%s", host, port)},
Timeout: 10 * time.Second,
Database: dbName,
Username: "",
Password: "",
})
return session
}
func produceDataMGO(conn *mgo.Session) {
dbConn := conn.Copy()
dbConn.DB("").C("test").Insert("")
dbConn.Close()
}
I detected a pretty weird thing that I don't understand. Behaviour is somehow different depending on how we create new connections (sync/async).
If we create connection synchronously - mongo closes this new connection immediately after calling .Close() method.
If we create connection asynchronously - mongo keeps this new connection alive even after calling .Close() method.
Why is it so?
Is there any other way to force-close connection socket?
Will it auto-close these open connections after a certain amount of time?
Is there any way to set a limit for the amount of connections MongoDB can expand its pool to?
Is there any way to setup an auto-truncate after a certain amount of time without high load?
It's connection pooling. When you "close" a session, it isn't necessarily closed; it may just be returned to the pool for re-use. In the synchronous example, it doesn't need to expand the pool; you're only using one connection at a time. In the concurrent example, you're using several connections at a time, so it may decide it does need to expand the pool. I would not consider 10 open connections to be cause for concern.
Try it with a larger test - say, 10 batches of 10 goroutines - and see how many connections are open afterward. If you have 100 connections open, something has gone wrong; if you have 10~20, then pooling is working correctly.

Is there a limit on the number of entities you can query from the GAE datastore?

My GCM Endpoint is derived from the code at /github.com/GoogleCloudPlatform/gradle-appengine-templates/tree/master/GcmEndpoints/root/src/main. Each Android client device
registers with the endpoint. A message can be sent to the first 10 registered devices using this code:
#Api(name = "messaging", version = "v1", namespace = #ApiNamespace(ownerDomain = "${endpointOwnerDomain}", ownerName = "${endpointOwnerDomain}", packagePath="${endpointPackagePath}"))
public class MessagingEndpoint {
private static final Logger log = Logger.getLogger(MessagingEndpoint.class.getName());
/** Api Keys can be obtained from the google cloud console */
private static final String API_KEY = System.getProperty("gcm.api.key");
/**
* Send to the first 10 devices (You can modify this to send to any number of devices or a specific device)
*
* #param message The message to send
*/
public void sendMessage(#Named("message") String message) throws IOException {
if(message == null || message.trim().length() == 0) {
log.warning("Not sending message because it is empty");
return;
}
// crop longer messages
if (message.length() > 1000) {
message = message.substring(0, 1000) + "[...]";
}
Sender sender = new Sender(API_KEY);
Message msg = new Message.Builder().addData("message", message).build();
List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).limit(10).list();
for(RegistrationRecord record : records) {
Result result = sender.send(msg, record.getRegId(), 5);
if (result.getMessageId() != null) {
log.info("Message sent to " + record.getRegId());
String canonicalRegId = result.getCanonicalRegistrationId();
if (canonicalRegId != null) {
// if the regId changed, we have to update the datastore
log.info("Registration Id changed for " + record.getRegId() + " updating to " + canonicalRegId);
record.setRegId(canonicalRegId);
ofy().save().entity(record).now();
}
} else {
String error = result.getErrorCodeName();
if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
log.warning("Registration Id " + record.getRegId() + " no longer registered with GCM, removing from datastore");
// if the device is no longer registered with Gcm, remove it from the datastore
ofy().delete().entity(record).now();
}
else {
log.warning("Error when sending message : " + error);
}
}
}
}
}
The above code sends to the first 10 registered devices. I would like to send to all registered clients. According to http://objectify-appengine.googlecode.com/svn/branches/allow-parent-filtering/javadoc/com/googlecode/objectify/cmd/Query.html#limit(int) setting limit(0) accomplishes this. But I'm not convinced there will not be a problem for very large numbers of registered clients due to memory constraints or the time it takes to execute the query. https://code.google.com/p/objectify-appengine/source/browse/Queries.wiki?repo=wiki states "Cursors let you take a "checkpoint" in a query result set, store the checkpoint elsewhere, and then resume from where you left off later. This is often used in combination with the Task Queue API to iterate through large datasets that cannot be processed in the 60s limit of a single request".
Note the comment about the 60s limit of a single request.
So my question - if I modified the sample code at /github.com/GoogleCloudPlatform/gradle-appengine-templates/tree/master/GcmEndpoints/root/src/main to request all objects from the datastore, by replacing limit(10) with limit(0), will this ever fail for a large number of objects? And if it will fail, roughly what number of objects?
This is a poor pattern, even with cursors. At the very least, you'll hit the hard 60s limit for a single request. And since you're doing updates on the RegistrationRecord, you need a transaction, which will slow down the process even more.
This is exactly what the task queue is for. The best way is to do it in two tasks:
Your api endpoint enqueues "send message to everyone" and returns immediately.
That first task is the "mapper" which iterates the RegistrationRecords with a keys-only query. For each key, enqueue a "reducer" task for "send X message to this record".
The reducer task sends the message and (in a transaction) performs your record update.
Using Deferred this actually isn't much code at all.
The first task frees you client immediately and gives you 10m to iterating RegistrationRecord keys rather than the 60s limit for a normal request. If you have your chunking right and batch queue submissions, you should be able to generate thousands of reducer tasks per second.
This will effortlessly scale to hundreds of thousands of users, and might get you into millions. If you need to scale higher, you can apply a map/reduce approach to parallelize the mapping. Then it's just a question of how many instances you want to throw at the problem.
I have used this approach to great effect in the past sending out millions of apple push notifications at a time. The task queue is your friend, use it heavily.
Your query will time out if you try to retrieve too many entities. You will need to use cursors in your loop.
No one can say how many entities can be retrieved before this timeout - it depends on the size of your entities, complexity of your query, and, most importantly, what else happens in your loop. For example, in your case you can dramatically speed up your loop (and thus retrieve many more entities before a timeout) by creating tasks instead of building and sending messages within the loop itself.
Note that by default a query returns entities in chunks of 20 - you will need to increase the chunk size if you have a large number of entities.

Does the SQL connection not get closed if you put the datareader in a using block?

So, I recently inherited a large project that uses the following data access pattern; unfortunately, this is resulting in a massive number of timeout exceptions related to connection pooling.
Timeout expired. The timeout period elapsed prior to obtaining a
connection from the pool. This may have occurred because all pooled
connections were in use and max pool size was reached"
It clear that the connections are leaking and not getting closed properly.
So, the framework has a DataAccess class with the method GetDataReader.
When the data reader is referenced, it is placed inside a using block, but connections are still leaking.
Does the fact that the connection is not explicitly closed or placed in a using block the reason why the connections are getting leaked?
Normally, I would wrap the connection in a using block AND wrap the data reader in a using block.
Obviously, this framework is very flawed, but would somehow using the option CommandBehavior.CloseConnection for the data reader resolve this issue?
None the external code accesses the SqlConnection directly and has to go through this DataAccess class.
public IDataReader GetDataReader(QueryDto dto)
{
DateTime current = DateTime.Now;
Database db = DatabaseFactory.CreateDatabase(dto.DatabaseName);
DbCommand cmd = db.GetStoredProcCommand(dto.StoredProcedureName);
if (dto.Params.Length > 0)
{
cmd = db.GetStoredProcCommand(dto.StoredProcedureName, dto.Params);
}
dto.Command = cmd;
cmd.CommandTimeout = dto.Timeout;
cmd.Connection = db.CreateConnection();
try
{
cmd.Connection.Open();
}
catch (SqlException ex)
{
// Handle Exception here...
throw;
}
return rdr;
}
Usage in some static repository class:
var query = new QueryDto
{
DatabaseName = "SomeDatabase",
Params = parms,
StoredProcedureName = "StoredProcedureName"
};
using (IDataReader dr = dataAccess.GetDataReader(query))
{
while (dr.Read())
{
// do stuff here
}
}
I think your problem is that the using statement is around a function that has open resources embedded in it. The using will not dispose of the connection that is opened inside GetDataReader. I think your are correct that the Connection itself needs to be in a using block. The using statement only calls Dispose on the object that is passed in, not any nested resources.

java.sql.SQLRecoverableException: Connection is already in use

In my java code, I am processing huge amount of data. So I moved the code as servlet to Cron Job of App Engine. Some days it works fine. After the amount of the data increases, the cron job is not working and shows the following error message.
2012-09-26 04:18:40.627
'ServletName' 'MethodName': Inside SQLExceptionjava.sql.SQLRecoverableException:
Connection is already in use.
I 2012-09-26 04:18:40.741
This request caused a new process to be started for your application, and thus caused
your application code to be loaded for the first time. This request may thus take
longer and use more CPU than a typical request for your application.
W 2012-09-26 04:18:40.741
A problem was encountered with the process that handled this request, causing it to
exit. This is likely to cause a new process to be used for the next request to your
application. If you see this message frequently, you may be throwing exceptions during
the initialization of your application. (Error code 104)
How to handle this problem?
This exception is typical when a single connection is shared between multiple threads. This will in turn happen when your code does not follow the standard JDBC idiom of acquiring and closing the DB resources in the shortest possible scope in the very same try-finally block like so:
public Entity find(Long id) throws SQLException {
Connection connection = null;
// ...
try {
connection = dataSource.getConnection();
// ...
} finally {
// ...
if (connection != null) try { connection.close(); } catch (SQLException ignore) {}
}
return entity;
}
Your comment on the question,
#TejasArjun i used connection pooling with servlet Init() method.
doesn't give me the impression that you're doing it the right way. This suggests that you're obtaining a DB connection in servlet's init() method and reusing the same one across all HTTP requests in all HTTP sessions. This is absolutely not right. A servlet instance is created/initialized only once during webapp's startup and reused throughout the entire remaining of the application's lifetime. This at least confirms the exception you're facing.
Just rewrite your JDBC code according the standard try-finally idiom as demonstrated above and you should be all set.
See also:
Is it safe to use a static java.sql.Connection instance in a multithreaded system?

Resources