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.


Reply via email to