Tuesday, September 25, 2007

JMS.. the fruit rollup of non-transactional resources

Everyone knows I love JMS. Almost all of my deployments take advantage of it and rightly so. Who couldn't love transactional, durable, scalable asynchronous processing.

One thing JMS is great for is wrapping resources that aren't JTA so they can "participate" in global transactions. Notice the quotes because the correct way of doing this would be to write your own JCA connector, but sometimes we don't have 3 months to read the spec.

A good example is if we want to save some stuff to a database and them write a file. If we were to do the following sudo-code, assume this is in a stateless session bean:



@TransactionalAttribute(REQUIRES_NEW)
public void doSomething()
{
Person p = new Person();
p.setName("Joshua");
entityManager.persist(p);

File f = new File("myStuff");
// write stuff to the file.
}



We actually don't know if our transaction succeeded until after this function has been executed. But wait... we have already written a file... Oops!

Enter JMS. Put this file-write code in a message-driven bean and have the above method pump a message to its destination and the message won't get sent unless the transaction completes.

Now there is one last thing to think about... what if the file write fails. Well, you have 2 options.

1) make sure the mdb rolls-back its transaction so the message will flow into a dlq and do your own compensation.
2) just set the destination to not use a dlq. This means if the message will keep being delivered until it can write a file. Not really ACID compliant but you won't loose any files.

No comments: