You should call TryDisposeUoW in one place, Message Completed.This is called
if there is a error or not, and intended for cleanup operations.

On Mon, Jun 1, 2009 at 7:39 PM, Mike Nichols <[email protected]>wrote:

> here is my unit of work module MessageProcessingCompleted handler. Placing
> this in MessageProcessingFailure handler seems to fix matters.
> NHProf was showing me that all the DTC errors were in the same session but
> I didn't think about the problems that creates. Let me be a little cheesy
> and say that if I didn't have NHProf showing me such clear boundaries on
> events I really am not sure how I was going to track this sucka down.
>
> Anyways, here is my new UnitOfWorkMessageModule for future victims of
> transaction torture :)
> public class UnitOfWorkMessageModule : IMessageModule
>     {
>
>         public void Init(ITransport transport)
>         {
>             transport.MessageArrived += transport_MessageArrived;
>             transport.MessageProcessingCompleted +=
> transport_MessageProcessingCompleted;
>             transport.MessageProcessingFailure +=
> transport_MessageProcessingFailure;
>         }
>
>         private void
> transport_MessageProcessingFailure(CurrentMessageInformation information,
> Exception exception)
>         {
>             TryDisposeUnitOfWork();
>
>             if (exception != null)
>             {
>                 Log.For(this).Error(exception.ToString());
>             }
>
>         }
>
>         public void Stop(ITransport transport)
>         {
>             transport.MessageArrived -= transport_MessageArrived;
>             transport.MessageProcessingCompleted -=
> transport_MessageProcessingCompleted;
>             transport.MessageProcessingFailure -=
> transport_MessageProcessingFailure;
>         }
>
>
>         bool transport_MessageArrived(CurrentMessageInformation arg)
>         {
>             UnitOfWork.Start();
>             return false;
>         }
>
>         void transport_MessageProcessingCompleted(CurrentMessageInformation
> obj, Exception exception)
>         {
>             if(exception!=null)
>             {
>                 Log.For(this).Error("An error occured on message process
> completion:" + exception);
>             }
>             else
>             {
>                 TryDisposeUnitOfWork();
>             }
>
>
>
>         }
>         private void TryDisposeUnitOfWork()
>         {
>             try
>             {
>                 if (UnitOfWork.IsStarted)
>                 {
>                     UnitOfWork.Current.Dispose();
>                 }
>             }
>             catch (Exception ex)
>             {
>                 Log.For(this).Error(ex.ToString());
>                 throw;
>             }
>         }
>     }
> On Mon, Jun 1, 2009 at 4:11 PM, Ayende Rahien <[email protected]> wrote:
>
>> Oh, that is probably it! You are not properly disposing the session in
>> that scenario?
>> Don't forget that if a message is failing, it is going to get retried.
>>
>> On Mon, Jun 1, 2009 at 7:08 PM, Mike Nichols <[email protected]>wrote:
>>
>>> The test I wrote passes (unfortunately). I just can't figure out why NH
>>> would try to insert again after the previous message was failed, almost like
>>> the session wasn't disposed in my UnitOfWork module after the  previous
>>> message was moved to the error queue...Let me check to make sure the message
>>> module MessageProcesSINGCompleted event is getting fired after a transaction
>>> failure....
>>>   On Mon, Jun 1, 2009 at 4:03 PM, Ayende Rahien <[email protected]>wrote:
>>>
>>>> Hm, can you try to write a test that reproduce this?
>>>>
>>>>
>>>> On Mon, Jun 1, 2009 at 6:55 PM, Mike Nichols 
>>>> <[email protected]>wrote:
>>>>
>>>>>
>>>>> Yes I see all those passing. Here's what's happening:
>>>>> 1. Send good message and all works
>>>>> 2. Send message that causes transaction exception (as before) :: App
>>>>> doesn't crash now (yeaay!)
>>>>> 3. Send good message : Message is received (therefore the transport is
>>>>> still alive even after previous exception) but before it is processed
>>>>> the previous bad transaction is attempted ONCE and so the whole
>>>>> processing fails...almost like the transaction wasn't disposed after
>>>>> the error queue handling was done. Interestingly, NHProf isn't showing
>>>>> all this in a new session either, but not sure that is truthful or
>>>>> not. The 'Error DTC Transaction prepre  (sic) phase failed' error pops
>>>>> up BEFORE the other message has a chance to fully process.
>>>>> Oi-vey
>>>>>
>>>>>
>>>>> On Jun 1, 2:57 pm, Ayende Rahien <[email protected]> wrote:
>>>>> > Hm, can you look at the tests that I committed, they are testing that
>>>>> the
>>>>> > message arrive in the error queue.
>>>>> >
>>>>> > On Mon, Jun 1, 2009 at 4:05 PM, Mike Nichols <
>>>>> [email protected]>wrote:
>>>>>  >
>>>>> >
>>>>> >
>>>>> >
>>>>> >
>>>>> > > Hm...the host isn't crashing now but the message that causes the
>>>>> error
>>>>> > > seems not to be moving to the errors queues, or, the transport is
>>>>> > > shutting down. i can't tell yet.
>>>>> >
>>>>> > > On Jun 1, 11:01 am, Ayende Rahien <[email protected]> wrote:
>>>>> > > > Okay, this is now fixed, have fun :-)
>>>>> >
>>>>> > > > On Mon, Jun 1, 2009 at 1:40 PM, Mike Nichols <
>>>>> [email protected]
>>>>> > > >wrote:
>>>>> >
>>>>> > > > > Man thanks Ayende
>>>>> >
>>>>> > > > > On Mon, Jun 1, 2009 at 10:13 AM, Ayende Rahien <
>>>>> [email protected]>
>>>>> > > wrote:
>>>>> >
>>>>> > > > >> Yes, I can.You need to use IEnlistmentNotification impl and
>>>>> register
>>>>> > > that
>>>>> > > > >> on the TX.
>>>>> > > > >> I'll have a fix shortly
>>>>> >
>>>>> > > > >> On Mon, Jun 1, 2009 at 1:01 PM, Mike Nichols <
>>>>> > > [email protected]>wrote:
>>>>> >
>>>>> > > > >>> Are you able to test this without all the NH dependency
>>>>> cruft? I want
>>>>> > > to
>>>>> > > > >>> keep hacking on this but can't figure out how to write a
>>>>> lighter test
>>>>> > > for it
>>>>> > > > >>> to stick in RSB code base. Just throwing
>>>>> TransactionExceptions
>>>>> > > doesn't work
>>>>> >
>>>>> > > > >>> On Mon, Jun 1, 2009 at 8:12 AM, Ayende Rahien <
>>>>> [email protected]>
>>>>> > > wrote:
>>>>> >
>>>>> > > > >>>> Sigh,
>>>>> > > > >>>> I reproduced the issue, not fun.
>>>>> >
>>>>> > > > >>>> On Mon, Jun 1, 2009 at 1:29 PM, Mike Nichols <
>>>>> > > [email protected]>wrote:
>>>>> >
>>>>> > > > >>>>> I think I have narrowed the problem to transaction commit
>>>>> failures
>>>>> > > > >>>>> that take place AFTER the 'Consume' invocation is made (ie
>>>>> in
>>>>> > > > >>>>> MessageCompleted). These exceptions are outside the scope
>>>>> of the
>>>>> > > > >>>>> try...catch wrapping the ProcessMessage call.
>>>>> > > > >>>>> In the code I have above the transaction tries to commit
>>>>> (in ATM)
>>>>> > > and
>>>>> > > > >>>>> then rolls back since SQL Server throws, aborting the
>>>>> transaction.
>>>>> > > > >>>>> When the TransactionScope attempts to Dispose in
>>>>> RQTransport
>>>>> > > > >>>>> ReceiveMessage method, the InternalTransaction throws since
>>>>> it was
>>>>> > > > >>>>> aborted, making the whole app crash since it is unhandled.
>>>>> >
>>>>> > > > >>>>> Any ideas on this? My attempts to handle
>>>>> TransactionException have
>>>>> > > so
>>>>> > > > >>>>> far just thrown RSB into a loop.
>>>>> >
>>>>> > > > >>>>> On May 30, 11:41 pm, Mike Nichols <
>>>>> [email protected]>
>>>>> > > wrote:
>>>>> > > > >>>>> > I have a test case here that demonstrates the problem. I
>>>>> changed
>>>>> > > > >>>>> > RQTransport on ReceiveMessage to catch
>>>>> > > TransactionAbortedException
>>>>> > > > >>>>> and
>>>>> > > > >>>>> > Debugger.Launch inside the catch statement.
>>>>> > > > >>>>> > Note this test is 'heavy' intentionally . RSB tries 5
>>>>> times to
>>>>> > > handle
>>>>> > > > >>>>> > the message but when the Session flushes the transaction
>>>>> aborts
>>>>> > > and
>>>>> > > > >>>>> > since the transaction reference is outside the
>>>>> try...catch in
>>>>> > > > >>>>> > ReceiveMessage it goes unhandled.
>>>>> >
>>>>> > > > >>>>> > First here is output from NHProf Error logging:
>>>>> > > > >>>>> > It seems like since the exception is thrown inside the
>>>>> > > > >>>>> > TransactionScope (tx) instead the inner try..catch is
>>>>> ignored and
>>>>> > > > >>>>> > hence the TransactionAbortedException goes unhandled in
>>>>> the app,
>>>>> > > > >>>>> > stopping it altogether.
>>>>> >
>>>>> > > > >>>>> > ERROR:
>>>>> > > > >>>>> > DTC transaction prepre phase failed
>>>>> > > > >>>>> > System.Data.SqlTypes.SqlTypeException: SqlDateTime
>>>>> overflow. Must
>>>>> > > be
>>>>> > > > >>>>> > between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
>>>>> > > > >>>>> >    at
>>>>> System.Data.SqlTypes.SqlDateTime.FromTimeSpan(TimeSpan
>>>>> > > value)
>>>>> > > > >>>>> >    at
>>>>> System.Data.SqlTypes.SqlDateTime.FromDateTime(DateTime
>>>>> > > value)
>>>>> > > > >>>>> >    at
>>>>> System.Data.SqlClient.MetaType.FromDateTime(DateTime
>>>>> > > dateTime,
>>>>> > > > >>>>> > Byte cb)
>>>>> > > > >>>>> >    at System.Data.SqlClient.TdsParser.WriteValue(Object
>>>>> value,
>>>>> > > > >>>>> > MetaType type, Byte scale, Int32 actualLength, Int32
>>>>> > > > >>>>> encodingByteSize,
>>>>> > > > >>>>> > Int32 offset, TdsParserStateObject stateObj)
>>>>> > > > >>>>> >    at
>>>>> System.Data.SqlClient.TdsParser.TdsExecuteRPC(_SqlRPC[]
>>>>> > > > >>>>> > rpcArray, Int32 timeout, Boolean inSchema,
>>>>> SqlNotificationRequest
>>>>> > > > >>>>> > notificationRequest, TdsParserStateObject stateObj,
>>>>> Boolean
>>>>> > > > >>>>> > isCommandProc)
>>>>> > > > >>>>> >    at
>>>>> System.Data.SqlClient.SqlCommand.RunExecuteReaderTds
>>>>> > > > >>>>> > (CommandBehavior cmdBehavior, RunBehavior runBehavior,
>>>>> Boolean
>>>>> > > > >>>>> > returnStream, Boolean async)
>>>>> > > > >>>>> >    at System.Data.SqlClient.SqlCommand.RunExecuteReader
>>>>> > > > >>>>> > (CommandBehavior cmdBehavior, RunBehavior runBehavior,
>>>>> Boolean
>>>>> > > > >>>>> > returnStream, String method, DbAsyncResult result)
>>>>> > > > >>>>> >    at
>>>>> System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery
>>>>> > > > >>>>> > (DbAsyncResult result, String methodName, Boolean
>>>>> sendToPipe)
>>>>> > > > >>>>> >    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
>>>>> > > > >>>>> >    at
>>>>> > > NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand
>>>>> > > > >>>>> > cmd)
>>>>> > > > >>>>> >    at
>>>>> > > NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation
>>>>> > > > >>>>> > expectation)
>>>>> > > > >>>>> >    at
>>>>> NHibernate.Persister.Entity.AbstractEntityPersister.Insert
>>>>> > > > >>>>> > (Object id, Object[] fields, Boolean[] notNull, Int32 j,
>>>>> > > > >>>>> > SqlCommandInfo sql, Object obj, ISessionImplementor
>>>>> session)
>>>>> > > > >>>>> >    at
>>>>> NHibernate.Persister.Entity.AbstractEntityPersister.Insert
>>>>> > > > >>>>> > (Object id, Object[] fields, Object obj,
>>>>> ISessionImplementor
>>>>> > > session)
>>>>> > > > >>>>> >    at NHibernate.Action.EntityInsertAction.Execute()
>>>>> > > > >>>>> >    at NHibernate.Engine.ActionQueue.Execute(IExecutable
>>>>> > > executable)
>>>>> > > > >>>>> >    at NHibernate.Engine.ActionQueue.ExecuteActions(IList
>>>>> list)
>>>>> > > > >>>>> >    at NHibernate.Engine.ActionQueue.ExecuteActions()
>>>>> > > > >>>>> >    at
>>>>> >
>>>>> > >
>>>>> NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions
>>>>> > > > >>>>> > (IEventSource session)
>>>>> > > > >>>>> >    at
>>>>> NHibernate.Event.Default.DefaultFlushEventListener.OnFlush
>>>>> > > > >>>>> > (FlushEvent event)
>>>>> > > > >>>>> >    at NHibernate.Impl.SessionImpl.Flush()
>>>>> > > > >>>>> >    at
>>>>> >
>>>>> > >
>>>>> NHibernate.Impl.AbstractSessionImpl.System.Transactions.IEnlistmentNotifica­tion.Prepare
>>>>>  > > > >>>>> > (PreparingEnlistment preparingEnlistment)
>>>>> >
>>>>> > > > >>>>> > TEST
>>>>> >
>>>>> > >
>>>>> ===========================================================================­===
>>>>> > > > >>>>> > I am attaching it here in the Files section to make it
>>>>> easier to
>>>>> > > > >>>>> read,
>>>>> > > > >>>>> > too:
>>>>> >
>>>>> > > > >>>>> > namespace Cei.MaterialsTesting.Bugs
>>>>> > > > >>>>> > {
>>>>> > > > >>>>> >         public class RSBBugs :
>>>>> > > > >>>>> > OccasionalConsumerOf<RSBBugs.ConsumerCompleteMessage>
>>>>> > > > >>>>> >         {
>>>>> > > > >>>>> >                 private WindsorContainer container;
>>>>> > > > >>>>> >                 private ManualResetEvent wait;
>>>>> >
>>>>> > > > >>>>> >                 public RSBBugs()
>>>>> > > > >>>>> >                 {
>>>>> > > > >>>>> >                         container = new
>>>>> WindsorContainer(new
>>>>> > > > >>>>> XmlInterpreter("Bugs/
>>>>> > > > >>>>> > RSBBugs.config"));
>>>>> > > > >>>>> >
>>>>> container.AddFacility("rhino.esb", new
>>>>> > > > >>>>> RhinoServiceBusFacility
>>>>> > > > >>>>> > ().AddMessageModule<UnitOfWorkMessageModule>());
>>>>> > > > >>>>> >                         container.AddFacility("trx", new
>>>>> > > > >>>>> RhinoTransactionFacility());
>>>>> > > > >>>>> >                         container.AddFacility("nh_uow",
>>>>> new
>>>>> > > > >>>>> NHibernateUnitOfWorkFacility(
>>>>> >
>>>>> > > new
>>>>> > > > >>>>> > NHibernateUnitOfWorkFacilityConfig(
>>>>> >
>>>>> > > > >>>>>   Assembly.GetAssembly(typeof
>>>>> > > > >>>>> > (BadDateEntity)))));
>>>>> >
>>>>> > > container.AddComponent<SQLMessageConsumer>();
>>>>> >
>>>>> > > > >>>>> >                         var cfg = new Configuration()
>>>>> >
>>>>> > > > >>>>> .SetProperty(Environment.ReleaseConnections, "on_close")
>>>>> > > > >>>>> >
>>>>> .SetProperty(Environment.Dialect,
>>>>> > > > >>>>> > "NHibernate.Dialect.MsSql2005Dialect")
>>>>> >
>>>>> > > > >>>>> .SetProperty(Environment.ConnectionDriver,
>>>>> > > > >>>>> > "NHibernate.Driver.SqlClientDriver")
>>>>> >
>>>>> > > > >>>>> .SetProperty(Environment.ConnectionString,
>>>>>  string.Format("Server=
>>>>> > > > >>>>> > (local);initial catalog={0};Integrated Security=SSPI",
>>>>> > > > >>>>> > "MaterialsTesting_Test"))
>>>>> >
>>>>> > > > >>>>> .SetProperty(Environment.ProxyFactoryFactoryClass, typeof
>>>>> > > > >>>>> > (ProxyFactoryFactory).AssemblyQualifiedName)
>>>>> > > > >>>>> >
>>>>> .SetProperty(Environment.ShowSql,
>>>>> > > > >>>>> "true")
>>>>> >
>>>>> > > .SetProperty(Environment.BatchSize,
>>>>> > > > >>>>> "10")
>>>>> >
>>>>> > > > >>>>> .SetProperty(Environment.GenerateStatistics, "true");
>>>>> >
>>>>> > > cfg.AddXmlFile("Bugs/BadDateEntity.hbm.xml");
>>>>> >
>>>>> > > > >>>>> >                         SessionFactory =
>>>>> > > cfg.BuildSessionFactory();
>>>>> > > > >>>>> >                         using (var session =
>>>>> > > > >>>>> SessionFactory.OpenSession())
>>>>> > > > >>>>> >                         {
>>>>> > > > >>>>> >                                 new
>>>>> > > SchemaExport(cfg).Execute(false,
>>>>> > > > >>>>> true, false,
>>>>> > > > >>>>> > session.Connection, null);
>>>>> > > > >>>>> >                         }
>>>>> > > > >>>>> >                         IoC.Initialize(container);
>>>>> > > > >>>>> >                 }
>>>>> >
>>>>> > > > >>>>> >                 protected ISessionFactory SessionFactory
>>>>> { get;
>>>>> > > set;
>>>>> > > > >>>>> }
>>>>> >
>>>>> > > > >>>>> >                 [Observation]
>>>>> > > > >>>>> >                 public void should_throw()
>>>>> > > > >>>>> >                 {
>>>>> > > > >>>>> >                         using(var bus =
>>>>> > > > >>>>> container.Resolve<IStartableServiceBus>())
>>>>> > > > >>>>> >                         {
>>>>> > > > >>>>> >                                 bus.Start();
>>>>> >
>>>>> > > > >>>>> using(bus.AddInstanceSubscription(this))
>>>>> > > > >>>>> >                                 {
>>>>> > > > >>>>> >                                         wait = new
>>>>> > > > >>>>> ManualResetEvent(false);
>>>>> > > > >>>>> >                                         bus.Send(new
>>>>> > > SQLMessage());
>>>>> >
>>>>> > > > >>>>> Assert.True(wait.WaitOne(TimeSpan.FromSeconds(60),false));
>>>>> > > > >>>>> >                                 }
>>>>> > > > >>>>> >                         }
>>>>> >
>>>>> > ...
>>>>> >
>>>>> > read more »- Hide quoted text -
>>>>> >
>>>>> > - Show quoted text -
>>>>>
>>>>>
>>>>
>>>>
>>
>>
>>
>
> >
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Rhino Tools Dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/rhino-tools-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to