Alright. I see what you mean now. That is exactly what I was trying to achieve: making the resources transactional and participate in a global tranaction scope. I thought this was the purpose of the transaction management facility. In my particular example, I have a db resource plus a source control provider and rsync transfers. And yes, I am planning to develop the last two in a transactional manner. What I would like is to avoid leaving the system in an inconsistent state, like in the following situation:
R1 commits R2 commits but fails In the current implementation the system blows up with an invalid transaction exception. Now, for me, this is not good enough. I thought about having a middle stage (Prepare for Commit), where the risk of failure is greater than in the vital Commit/Rollback stage, where all you need to do is a switch to "live" or a cleanup, respectively. True, bad things could happen in the last stage as well, but the risk would be minimal. Another idea would be, as you said, having the resources store a history of state so that they could rollback even after they commited, but in this case we break the concept of isolation. On Mar 15, 12:08 pm, "Henrik Feldt" <[email protected]> wrote: > Hello, > > Your first post: > > Transaction manager receives a green light for resource chain commit > and calls every resource enlisted. Resource1 tries to commit but fails with > an exception. AbstractTransaction cathes the exception and stores it for > later use; the transaction is also given an invalid state. Resource2 is > called now (surprisingly for commit!). > > Previously this was true in the code; during commit -- even if one resource > failed, all resources' commit method was called. However, now the code is > like this: > > _Sem.AtomWrite(() => > { > AssertState(TransactionStatus.Active); > Status = TransactionStatus.Committed; > > }); > > _Sem.AtomRead(() => { > > _SyncInfo.ForEach(s => _Logger.TryLogFail(s.BeforeCompletion)); > > foreach (var r in _Resources) > { > try { r.Commit(); } > catch (Exception e) > { > SetRollbackOnly(); > throw new CommitResourceException("Transaction could > not commit because of a failed resource.", > e, r); > } > } > > }); > > try > { > _Logger.TryLogFail(InnerCommit) // commit transaction > .Exception(e => { throw new TransactionException("Could not > commit", e); });} > > finally > { > _Sem.AtomRead(() => _SyncInfo.ForEach(s => > _Logger.TryLogFail(s.AfterCompletion))); > > } > > So as you can see, the first resource that fails instructs the transaction > manager (transitively since rollbackonly is a property of a transaction), > that the transaction shouldn't be committed. > > So indeed this has changed. > > I wasn't with this project from the beginning, but in my mind this is a > wrapper around transacted resources, not a project implementing 2PC or even > 1PC; in order to do so we would have to keep a log file that is flushed to > and make sure that the transaction manager can restore state after a system > restart or failure. > > Instead what the project does is to call the appropriate kernel transaction > and resource managers, implemented in MS DTC, the kernel or the database of > the choice. > > As such, resources aren't fulfilling the properties of ACID; but rather a > convenience for use together with transactions. They can keep track of state > changes before and after commits but shouldn't be expected to be > transactional themselves, like it seems you are trying to make them. For > example, the isolation property between a resource and its transaction > doesn't garantuee that the resource won't see transient data, so it doesn't > hold. > > But looking at your initial message and what the code is now, I would say > that your specific case has been fixed for. It might be however that I have > misunderstood what you are after. If you want multiple transactions, why > can't you do: > > using (var t = new TransactionScope()) > { > IoC.Resolve<Intercepted1>().Invoke(); > IoC.Resolve<Intercepted2>().Invoke(); > t.Complete() > > } > > ... > > [Transactional] class Intercepted1 { [Transaction] public virtual void > Invoke(){}} > [Transactional] class Intercepted2 { [Transaction] public virtual void > Invoke(){}} > > If these use different end-point resources, e.g. different servers running > databases, or TxF + SQL Server for example, the default transaction mode > would be enlist and both would be enlisted in DTC, giving you 2PC and ACID > across Intercepted1 and Intercepted2. > > If this doesn't match your requirements, could you send me some code that > demonstrates the functionality you are after? You don't have to send it on > the mailing list if it's proprietary code. > > Cheers, > Henrik > > -----Original Message----- > From: [email protected] > > [mailto:[email protected]] On Behalf Of MoonStorm > Sent: den 15 mars 2010 12:26 > To: Castle Project Users > Subject: Re: Transaction Management - The chain of resources not rolled back > if one fails > > I had some time to look at the new code. Unfortunately the issue > presented in my first post is still present. Thinking about it though, > this is a case that can't be easily solved. Probably a two stage > commit would be able to handle this properly, IF the workhorse is > implemented in an aditional "prepare for commit" stage (i.e. the > resource is pushing the data in a temp remote container in the > "prepare for commit" stage and the "commit" afterwards is just > performing a switch remotely to make the data available for retrieval > by others). > > I would love to hear your thoughts about this. > > -- > You received this message because you are subscribed to the Google Groups > "Castle Project Users" 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 > athttp://groups.google.com/group/castle-project-users?hl=en. -- You received this message because you are subscribed to the Google Groups "Castle Project Users" 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/castle-project-users?hl=en.
