Hi,
I recently been working with the Castle.Components.Scheduler and Jobs. The job runs in a NServiceBus host on Version: 2.0.0.1219
Basically, I created a Job that implemented IJob and had constructor injection for the NHibernate Session.
<!–Castle.Components.Scheduler–>
<component id=”TheJob”
service=”Castle.Components.Scheduler.IJob”
type=”Romiko.TheJob, Romiko”
lifestyle=”transient”/>
public class TheJob : TheJobBase, IJob { public TheJob(Idependency1 dep1, Idependency2 dep2, ISession myNHSession) : base(dep1, dep2,myNHSession) ) { } public override bool Execute(JobExecutionContext context) { Process(context); return true; }
I colleague of mine, Matthew Wills, from Readify has been telling me how much NHProf can save you time, and indeed today it was proved
The process method above runs a series of job steps which execute 3 SQL select staments.
NHProf was moaning about the Session being shared:
Alert: Using a single session in multiple threads is likely a bug
Alert: Use of implicit transactions is discouraged
We noticed that subsequent job runs were using the same session!
See above, that 1 session is being used by the job, which runs all the time, this is not good at all for performance. The above shows the job running 4 to 5 times, each time executing 3 statements.
So, what we did, was remove the Session from the constructor injection, as we found a bug where a session was being created on one thread (in constructor) and then used in another thread (in the execute method).
To solve the problem above, we used Windsor to resolve the dependency in the execute method instead.
public override bool Execute(JobExecutionContext context) { _session = WindsorAccessor.Container.Resolve<ISession>(); Process(context); return true; }
Now, when we run NHProf, we get a sessoin per job and no longer hold a session for along time on a long running process within NServiceBus.
Lets rerun the code now and see how it works when we run 4 to 5 jobs
From the above, we can now see different sessions per JOB CYCLE. This will consume less resources and we solved the red nasty warnings in NHProf.
Mathew pointed out that we can go further, and optimised the 3 transactions above to be called in BATCH. So we can optimise the QueryOver methods to use Future operations, which will then batch the 3 transactions, which I can then use from within the job process, thus reducing each job cycle from 3 database calls to 1.
What i did was use something along the line of Future in my code and then delay looping through my result set until the last minute, so some code shuffling around
return Session.QueryOver<RomikoTable1>() .Where(x => x.CreatedDate >= RegDate && x.CreatedDate <= dateUnreg && x.Count == pollCount && x.BobTheBuilder == null) .JoinQueryOver(y => y.TableTwo) .JoinQueryOver(z => z.PostManPat).Where(a => a.Id == PostManPatId) .Future<RomikoTable1>();
Now check the BATCHING, hence less connections, notice duration is for all of them, where before you see a duration for each query.
I would like to thank Matthew Wills for show me some new cool tools that will definitely help me along the road in the future!
I would say that NHProf is definitely worth buying!
That is Matthew Wills, with two Ts. 🙂
As I said to you earlier, anyone working with EF / NHibernate etc without one of Oren’s profilers is literally burning their employer’s / client’s money. They really are amazing in the insight in what they provide.