We have a need in our app to support multiple "connections" to different
databases, with each connection supporting the same set of mappings. We
have a huge number of mappings (this is a decade-old legacy application),
and each connection and database has the same schema. We recently added a
feature to the application that allows a user on one connection to view
data on all of the other connections, which requires having all of the
connections available at the time of the request.
Bootstrapping a single connection can take up to 20 seconds over a slow
wire. When one of our customers tried to view data on 7 connections, the
application (unsurprisingly) timed out. To address this, we are taking a
two-pronged approach:
1. bootstrap all connections prior to login of the first user (at
app_start); and
2. at bootstrap, create the session factories for each connection in a
multi-threaded environment to reduce the timeout problem.
The second approach is proving to be problematic. When calling
BuildSessionFactory in a multi-threaded environment, the logs show that the
factories are being constructed serially. (i.e. I spin off the threads at
time A, and they come back at times B, B+10, B+20, B+30, etc). Another
developer reporting setting up an integration environment to test this, and
received a duplicate key exception from within NHIbernate. I have not yet
had time to review that error or his code, but it points to something
problematic with using nHibernate in a multi-threaded environment.
Would somebody mind taking a look at the following code and commenting on
our approach? Thanks very much.
public void ConstructSessionFactories(IEnumerable<string>
connectionNames)
{
var maps = connectionMap.Map.Where(m =>
connectionNames.Contains(m.Key)).Select(m => m.Value);
maps.ForEach(info =>
{
if (factoryMap.ContainsKey(info.ConnectionString)) return;
WaitForCompletionIfFactoryUnderConstruction(info.ConnectionString);
if (factoryMap.ContainsKey(info.ConnectionString)) return;
var task = new Task(() => CreateNewFactory(info));
task.ContinueWith(FactoryConstructed,
TaskContinuationOptions.OnlyOnRanToCompletion);
task.ContinueWith(FactoryNotConstructed,
TaskContinuationOptions.NotOnRanToCompletion);
task.ContinueWith(FactoryConstructionCausedError,
TaskContinuationOptions.OnlyOnFaulted);
factoriesUnderConstruction[info.ConnectionString] = task;
task.Start();
});
}
protected virtual ISessionFactory CreateNewFactory(ConnectionElement
info)
{
if (factoryMap.ContainsKey(info.ConnectionString)) return
factoryMap[info.ConnectionString];
logger.DebugFormat("Creating new SessionFactory for connection
'{0}'", info.Name);
var cfg = configurationProvider.Get(info);
ExposeConfiguration(cfg);
configData.AddOrUpdate(info.Name, cfg, (key, oldValue) => cfg);
var factory = cfg.BuildSessionFactory();
factoryMap[info.ConnectionString] = factory;
return factory;
}
private void WaitForCompletionIfFactoryUnderConstruction(string
connection)
{
while (factoriesUnderConstruction.ContainsKey(connection))
{
Task task;
factoriesUnderConstruction.TryGetValue(connection, out task);
if (task != null) task.Wait();
}
}
--
You received this message because you are subscribed to the Google Groups
"nhusers" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/nhusers?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.