Search |
||
Handling Poison Messages with GlassfishPosted by felipegaucho on September 24, 2009 at 4:06 AM PDT
Poison messages are basically delivery deadlocks caused by a continuous redelivery of a message to a JMS Queue or Topic. That usually happens due to a code bug or configuration problems in the project. How to reproduce poison messagesThe easiest way of reproducing the poison messages issue is to create a Message Driven Bean and then to throw an exception in its onMessage method, like the example below.
@MessageDriven(activationConfig = {@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")}, mappedName = "MyQueue")
public class RegistrationMessageBean implements MessageListener {
@Override
public void onMessage(Message registration) {
throw new RuntimeException("poison message");
}
}
Fixing the JMS deadlockWhat happens is that JMS relies on transactions to guarantee that all messages in a Queue will be delivered despite any temporary problems in the message consumer. If a message consumer (MDB) throws an exception, the JMS server tries to redeliver the message (transaction rollback). Only if a method consuming the message finishes without error the transaction will be committed and then the message will be removed from the Queue (acknowledged). In the sample above, the message consumer will always throw an exception and due to that the server will always redeliver the message - a deadlock. The workarounds to fix such a problem are:
The second solution is a robust way of guaranteeing the consume
of a message despite any problems. Not so elegant, but without
exceptions in the A more complicated scenario with sub-transactionsThe previous solution works for the general case, a simple Java
code inside the @PersistenceUnit(name = "arenapuj")
protected EntityManagerFactory emf;
@Override
public void onMessage(Message registration) {
try {
create(new MyJpaEntity());
} catch(Exception error) {
logger.severe("I am ignoring the JMS exception: " + e.getMessage());
}
}
public MyJpaEntity create(final MyJpaEntity entity) throws Exception {
EntityManager manager = emf.createEntityManager();
try {
manager.persist(entity);
manager.flush();
return entity;
} finally {
if (manager != null && manager.isOpen()) {
manager.close();
}
}
}
The robust How to avoid poison messages caused by sub-transactions?You should annotate the method with the first sub-transaction
with
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public MyJpaEntity create(final MyJpaEntity entity) throws Exception {
EntityManager manager = emf.createEntityManager();
try {
manager.persist(entity);
manager.flush();
return entity;
} finally {
if (manager != null && manager.isOpen()) {
manager.close();
}
}
}
Done, now your JMS method is decoupled from the new JPA transaction and if the JPA code rolls back, the JMS message will be acknowledged anyway. Disclaimer: I am abusing the terms " Handling problems outside the codeOther common JMS scenario is to have resources problems, like connection failures, database down, etc. If we have a message consumer down and a message producer working, the producer will try to send a message, fail and try to send the message again. It would cause another type of deadlock, but the Java EE containers provide a set of configuration options to prevent such problems. The ActivationSpec for Message Driven Beans specifies two annotations to workaround activating problems:
You may check those configurations in your code review, but it is not so critical since their default values are reasonable for the common scenarios. And you need to know container specific attributes. The Glassfish V3 activation properties changed a bit, and I suppose for the other containers we will find different names. Fortunately we can expect that all defaults work fine and we are not forced to dig in product-specific details all the time. SummaryJMS is one of the most powerful java EE resources available for developers and architects, but it is very important that anyone designing such applications knows in deep the specification and also some implementation tricks. Poison messages can make your server and eventually the whole host machine to hang for hours - forcing a machine to restart. It is a common problem, in my opinion weakly supported by the containers and a problem we should know about. The goal of this blog entry is just to give you a chance to identify the poison messages problem of your application. to know more about JMS and its details, you need to read more and the links below seem to be a good starting point:
Aknowledgment: a special thanks for Marina Vatkina and Nigel Deakin for their friendly support through the Glassfish's mailing list. And a kudo to "The Professor" and his wise hints on this topic. »
Comments
Comments are listed in date ascending order (oldest first)
|
||
|