View Full Version : NMS Support of COM+ Transactions
txpet2
02-23-2008, 02:20 PM
I am doing a "proof of concept" for integration of ActiveMQ into a .NET project. I have been successful in sending and receiving messages inside of a COM service using your implementation of NMS. Now I need to integrate transactional support via COM+. Is their any way of hooking into the COM+ transaction?
I went searching through the Spring.Messaging.NMS source code. In ConnectionFactoryUtils.cs, I saw some references to "//TODO bring in new Spring.Data library to Integration project which has this method in interface" with regards to the transactional support. As another alternative, I could use Spring's transactional support. Has this been implemented into NMS yet.
Mark Pollack
02-25-2008, 05:30 PM
Hi,
I believe that ActiveMQ does not support distributed transactions in .NET. I saw your post on the ActiveMQ list as well, so they should provide the definitive answer. I am not sure what James meant by that comment, I believe that at the time that code was written the version of Spring.Data that was local to the NMS build did not have those methods on the ITransactionSynchronization interface. I think I corrected that shortly afterwards, so the comment doesn't really pertain to what you are trying to do.
I have a couple of questions/options for you. I assume you want to integrate with COM+ transactions because you want to perform something like a database operation and a messaging operation within the same (distributed) transaction? If you do, and ActiveMQ doesn't support it, then it would likely be implemented using features in the System.Transactions namespace as compared to COM+/EnterpriseServices. Even easier, would be to switch to using MSMQ for this case, perhaps creating a ActiveMQ/MSMQ bridge. (There is a feature request for this in ActiveMQ here (https://issues.apache.org/activemq/browse/AMQ-438))
That said, you may want to consider if you can avoid doing a distributed transaction (with or without COM+). Often it can be avoided. This ActiveMQ doc (http://activemq.apache.org/should-i-use-xa.html) sums up the basic points.
The scenario is that you would create a SimpleMessageListenerContainer with the Nms Session ack mode set to transactional. Within the messaging callback you call another class to do database work. The database work would use typical Spring.NET transaction features, AdoPlatformTransactionManager/AdoTemplate and say the [Transaction] attribute for declarative transaction management. Note this is a local transaction. After your database work finishes, you can then perform additional messaging operations, say sending a message. In case the program fails before the NMS session is closed, then that message will be redelivered. To avoid this, you should check on the message redelivered flag, if set then one typically checks the database to see if the expected processing occurred, and then take appropriate actions. This could be discarding the message, or reprocessing the message. The upside is that this is more performant than a distributed transaction but the downside is you need to take care of duplicate detection.
One thing that we can provide that is currently missing in the .NET version (but present in the Spring.Java) is the NmsTransactionManager. The NmsTransactionManager will bind the Connection/Session used when receiving the message to the current thread. NmsTemplate would then use that connection/session for all operations. If a database rollback occurs, then the Nms session will be rolled back automatically. This is useful to get easy access to the transacted NMS session, if you are going to send additional messages in the service layer.
Keep the conversation going, I'd like to know what you end up doing.
Cheers,
Mark
txpet2
02-27-2008, 07:36 AM
Thank you for your thorough response. I was trying to do distributed transactions.
Having abandoned that, I went for the suggested approach of committing the database transaction and then commit the NMS transaction. I set the SessionAcknowledgeMode property on the listener to Apache.NMS.AcknowledgementMode.Transactional and created a listener that implements ISessionAwareMessageListener. This exposed the ISession instance so that I could commit and rollback the AQ message. Needless to say, I was delighted to see the message "DoInvokeListener.ISessionAwareMessageListener not implemented" in the logs.
Two questions:
1. Is there another way to get to the session or implement AQ transactions?
2. It doesn't look that complicated to complete ISessionAwareMessageListener. Wouldn't it just be a matter on creating the OnMessage(message,session) method signature in the interface? Am I overlooking something?
Thanks again!
Mark Pollack
02-27-2008, 04:58 PM
Hi,
I've implemented the method now. It isn't that complicated aside from the fact there is an option to expose a new session, instead of the one of the listener thread. I've attached the new impl, just in case you can't get it from cvs.
There is another option, which would be to bind the connection factory, connection, session to thread local storage (TLS) and then have NmsTemplate be aware to look in TLS to get its NMS resources. This is done in the case of DefaultMessageListenerContainer in Java but not for SimpleMessageListenerContainer. I'm following up on that. All this means is that it would avoid you having to pass around the session information.
Cheers,
Mark
FYI - the NMS code will be move to a better home in the next few weeks and the plan is to have it (as well as a NMS WCF Channel) as part of Spring .NET 2.0
txpet2
02-28-2008, 01:19 PM
Thanks...
That worked. I am now able to basicly replicate the MDB functionality inside of the COM+ server using ActiveMQ.
My proof of concept has been successful. We will be migrating the functionality into production.
vBulletin® v3.7.3, Copyright ©2000-2009, Jelsoft Enterprises Ltd.