tags:

views:

2545

answers:

3

Hi all,

I'm developing and application that runs as a Windows service. There are other components which include a few WCF services, a client GUI and so on - but it is the Windows service that access the database.

So, the application is a long-running server, and I'd like to improve its performance and scalability, I was looking to improve data access among other things. I posted in another thread about second-level caching.

This post is about session management for the long-running thread that accesses the database. Should I be using a thread-static context? If so, is there any example of how that would be implemented.

Every one around the net who is using NHibernate seem to be heavily focussed on web-application style architectures. There seems to be a great lack of documentation / discussion for non-web app designs.

At the moment, my long running thread does this:

  1. Call 3 or 4 DAO methods
  2. Verify the state of the detached objects returned.
  3. Update the state if needed.
  4. Call a couple of DAO methods to persist the updated instances. (pass in the id of the object and the instance itself - the DAO will retrieve the object from the DB again, and set the updated values and session.SaveOrUpdate() before committing the transaction.
  5. Sleep for 'n' seconds
  6. Repeat all over again!

So, the following is a common pattern we use for each of the DAO methods:

  • Open session using sessionFactory.OpenSession()
  • Begin transaction
  • Do db work. retrieve / update etc
  • Commit trans
  • (Rollback in case of exceptions)
  • Finally always dispose transaction and session.Close()

This happens for every method call to a DAO class. I suspect this is some sort of an anti-pattern the way we are doing it.

However, I'm not able to find enough direction anywhere as to how we could improve it.

Pls note, while this thread is running in the background, doing its stuff, there are requests coming in from the WCF clients each of which could make 2-3 DAO calls themselves - sometimes querying/updating the same objects the long running thread deals with.

Any ideas / suggestions / pointers to improve our design will be greatly appreciated. If we can get some good discussion going, we could make this a community wiki, and possbily link to here from NHForge.org Krishna

+5  A: 

There seems to be a great lack of documentation / discussion for non-web app designs.

This has also been my experience. However, the model you are following seems correct to me. You should always open a session, commit changes, then close it again.

steffenj
+1. I seen this general advice several times: The SessionFactory is expensive. Only create it once. Sessions are cheap.
snicker
A: 

I agree, there aren't many examples for stateful apps. I'm thinking of doing the following:

Like you I have a windows service hosting a number of WCF services. So the WCF services are the entry points. Ultimately all my WCF services inherit from AbstractService - which handles a lot of logging and basic DB inserts/updates.

In one of the best NHibernate posts I've seen, a HttpModule does the following: [see http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx]

private void BeginTransaction(object sender, EventArgs e) { NHibernateSessionManager.Instance.BeginTransaction(); } private void CommitAndCloseSession(object sender, EventArgs e) { try { NHibernateSessionManager.Instance.CommitTransaction(); } finally { NHibernateSessionManager.Instance.CloseSession(); } }


So perhaps I should do something similar in AbstractService. So effectively I'll end up with a session per service invocation. If you examine the NHib best practices article link above, you'll see that the NHibernateSessionManager should deal with everything else, as long as I open and close the session (AbstractService constructor and destructor).

Just a thought. But I'm experiencing errors because my session seems to be hanging around for too long, and I'm getting the infamous error - NHibernate.AssertionFailure: null id in entry (don't flush the Session after an exception occurs).

A: 

You can also flush the session without actually closing it and it achieves the same thing. I do.

Nick