In the context of a windows web service that's meant to run jobs, we try to reuse the NHibernate DAL we developed for the web application.
For session management we have two options, each one having its advantages and drawbacks:
Stateful session
Going to grow a lot as it keeps track of everything (L1/session cache)
Needs to be carefully closed, session disposal doesn't seem to be enough to clear L1 cache (what I noticed using memory profiler)
Stateless Session
Currently fails to reuse mappings. All bags declared with "lazy=true" ends up with the following exception (even though the session has not be closed):
Initializing [...] failed to lazily initialize a collection of role:
[...], no session or session was closed
Obviously, we cannot update the mappings (they are shared with the web app) with lazy="false", it's gonna be a huge drawback for performances
Cannot interact with L2 cache: when shared L2 cache will be deployed, the service will be unable to invalidate L2 cache data in order for web application to have fresh up-to-date data
NHibernate has proven to be good until now, we have successfully used stateful session and NHibernate LINQ it in a web context, with structuremap for dependency injection.
My questions are:
Are there any good solutions to use NHibernate in a long running thread?
I'd prefer to use stateful session, but how to avoid memory leak?
Problem solved! There were actually a couple of problems.
First one was about instances' scope, and multi-threading:
Create a new session for each thread.
As soon as the thread finishes its work, clean all the instances attached to the thread. With StructureMap, within the thread, use new HybridLifecycle().FindCache().DisposeAndClear();. It will cause the session attached to the thread to close and dispose.
When the lifecycle is thread scoped, StructureMap uses a ThreadStatic variable to keep a reference to the object cache. So the trick is to call StructureMap's ObjectFactory within the thread. Initially, in our application, a main thread was responsible for creating new threads, and call the ObjectFactory. That's the major mistake we did, and were indeed unable to clean the threads once their job was done.
Session type:
No need to use a StateLessSession, as soon as the StateFul sessions instantiated are carefully disposed. In our case, StatelessSession have too many drawbacks (cache management is the main)
Important remark: be careful to instantiate NHibernate NHibernate Session Factory only once!
When NHibernate instances are managed carefully, there is no memory leak.
It's never a good idea to keep a stateful session open in a long running process.
My suggestion is to redesign your process to separate database related code from non-database related code so any database related operation can be kept within a short-span session.
Related
I have this administration site that is using (Fluent) NHibernate for data access. As has been stated elsewhere the initialization of the SessionFactory is slow due to creation of the Configuration object. The suggested solution is to serialize the Configuration object to disk and then reuse this untill the entity assembly or fluent initialization assembly changes.
In theory these sound very elegant and appealing. In practice even with a 1-entity model, deserializing the Configuration takes about 500ms and creating the SessionFactory another 500ms. (This is comparable to the startup time with no serialization, but I suspect the gain will be apparent once I put more entities in there.)
After IIS recycles my Application Pool, it doesn't start it up again untill a new request comes in. So with default recycle management of IIS (every 29h), and a probable scenario of an administrator logging into my administration site once a day, that 1s delay will happen almost every time this admin logs in, giving the impression of a slow starting site.
So, I wonder if there is any way to tell IIS/WAS to actually start the replacement Application Pool as part of the recycling instead of waiting untill the next request comes in? I realize this goes against the idea of WAS trying to keep as few concurrent application pools running at any given time, but it would solve my problem (as I assume my ServiceHostFactory+ServiceHost would be created as soon as the Application Pool starts up).
Will IIS 7 autostart feature help you? Also, you can implement System.Web.Hosting.IProcessHostPreloadClient interface to make sure the application is up when the pool is up (see this blog post for an example).
I am writing an application and I finally have it saving to the database correctly. However, I have a few problems and was wandering if someone could help point me in the right direction.
During my application load I fire off an NHibernate initialization thread that initializes NHibernate and then fires off 3 separate threads to load 3 of my objects, in order to split up and optimize the load time.
I was originally creating a temporary session in each of these threads in order to query the objects from the database; however, I was running into problems accessing one of the collections of my object saying that a session is not open or it has been closed. I have a static session that is globally accessible throughout my Windows application and when it was calling the GetEnumerator for the collection the state of this session was still open.
I believe it has to do with the fact that the Intersection, the class in question, was loaded from a different session in the thread during the init process. Loading all the objects form the same session works fine; however, I do run into exceptions from time to time with errors regarding sessions being used in a non thread safe manner.
My question then is this. Is there a way to "merge" sessions onto my global session? What can I do to set the Intersection class to where it has an open session in order to load the collection? Is the problem that I need to open the session of the static global program session in the main thread? Or am I going to be unable to thread the loading of the 3 different classes during my init process into 3 separate threads?
you can associate the object-graphs loaded with the other sessions with you main-session.
If the objects may have changed then MainSession.Merge(obj) because it will load the Db-State to know what changed.
If the objects haven't changed then MainSession.Lock(obj, LockMode.None) is enough to associate it with the main-session.
After that you you can use the objects as if they were loaded with your main session
We use one (read-only) session which we disconnect as soon as we retrieve the data from the database. The data retrieved, often has lazy-loaded properties which are not initialized yet.
When we try to access the properties, the following exception gets thrown:
NHibernate.LazyInitializationException
Initializing[NHibernateTest.AppUser#16]-failed to lazily initialize a collection of role: NHibernateTest.AppUser.Permissions, session is disconnected
Is there a way (interceptor) to automatically detect that the application is trying to access an uninitialized property, so that the interceptor can quickly open the connection and close it after the unit of work?
Fetching everything at once would nullify the usage of laziness.
There is no efficient way to do that. The idea is that you keep the session open until your done with the session. There should be one session per unit of work. (a session is kind of unit of work actually).
Fetching everything your need in one query is more efficient than fetching everything you need in multiple queries, so I don't agree with your last statement. Lazy loading is useful for lazy programmers (like me) but is never more efficient than eager loading. Lazy loading can save you some programming time, but you still have to watch out for to many queries being executed (select N+1)
What are your experiences with the latest version of NHibernate (2.0.1 GA) regarding disconnected scenarios?
A disconnected scenario is where I fetch some object graph from NHibernate, disconnect from the session (and database connection), do some changes in the object graph (deleting in collections, adding entities, updating entities) and then reconnect and save....
We tried this in a client-server architecture. Now we are moving to DTO (data transfer objects). This means, the detached entities are not directly sent to the client anymore, but specialized objects.
The main reason to move in this direction is not NHibernate, it is actually the serialization needed to send entities to the client. While you could use lazy-loading (and you will!) while you are attached to the session, you need to get all references from the database to serialize it.
We had lots of Guids instead of references and lots of properties which are mapped but not serialized ... and it became a pain. So it's much easier to copy the stuff you really want to serialize to its own structure.
Besides of that - working detached could work well.
Be careful with lazy loading, which will cause exceptions to be thrown when accessing non loaded objects on a detached instance.
Be careful with concurrency, the chance that entities had changed while they where detached is high.
Be careful if you need some sort of security or even if you want your server alown to make some data changes. The detached objects could potentially return in any state.
You may take a look on session methods SaveOrUpdateCopy and Merge.
Here is an article which gives you more details:
NHibernate feature: SaveOrUpdateCopy & Merge
I was reading that the initial load time for the configuration can be fairly long in nHibernate depending on the # of mapping tables, etc.
Is this done once and stored in session or cache?
Will it happen every time the ASP.NET process recycles?
A Configuration object is normally associated to an ISessionFactory. If you have lots of mappings building (by calling cfg.BuildSessionFactory) a session factory might be slow. That's why you need to construct a session factory only once and use it throughout your entire application. In an ASP.NET application when the process recycles, you will lose the reference to this session factory and it needs to be reconstructed again.
If you find it is extremely slow to construct your session factory you could improve performance by disabling the reflection optimizer : Environment.UseReflectionOptimizer = false (cf doc)
The Configuration is used to build the ISessionFactory. It's a one shot deal - which will occurs at the application startup.