My basic problem:
the MessageDriven
bean throws an Exception
somewhere, which leads to a rollback in the JMS Queue
until it just blows up and the server breaks down. I can't even look for the Exceptions
to solve the problem because the server-logs grow to a few hundred MB in only a few Minutes.
What I am looking for:
a way to first clear the JMS Queue
and then stop the rollbacks once and for all.
This is what I do:
the object stateless bean to Message-Driven Bean here it throws I want to send send the ObjectMessage to receive the message the Exception +-----------+ +-----------------+ +-----------------+ +----------+ | MyObject |----->| MessageProducer |------->| MessageReceiver |---->| do stuff | +-----------+ +-----------------+ +-----------------+ +----------+
The object I send is a simple serializable
POJO.
The MessageProducer looks like this:
@Stateless
public class MessageProducer{
@Resource(mappedName = "jms/JMSConnectionFactory")
private ConnectionFactory connectionFactory;
@Resource(mappedName = "jms/MessageReceiver")
Queue messageReceiver;
public void sendMessage(PostContainer postContainer){
MessageProducer messageProducer;
// try with resources to close everything on Exception
try(Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE)){
messageProducer = session.createProducer(messageReceiver);
ObjectMessage objectMessage = session.createObjectMessage();
objectMessage.setObject(myObject);
objectMessage.setJMSRedelivered(false); // this doesn't seem to have any effect
messageProducer.send(objectMessage);
messageProducer.close();
}catch(Exception ex){
System.out.err("error when sendingMessage .. ignoring"); // when "ignoring" the Exception I thought to at least save me the enormous log messages
}
}
}
The message bean looks like this:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/MessageReceiver")
})
public class MessageReceiver implements MessageListener{
public MessageReceiver(){
}
@Override
public void onMessage(Message message){
try{
if(message instanceof ObjectMessage){
ObjectMessage objectMessage = (ObjectMessage) message;
MyObject myObject = (MyObject) objectMessage.getObject();
doStuff(myObject); // the method that handles the incoming object - here the Exception gets thrown
}
}catch(Exception ex){
System.err.println("message could not be received: " + ex.getMessage()); // still trying to ignore exceptions here
}
}
}
Some part of the Exception
javax.ejb.TransactionRolledbackLocalException: Exception thrown from bean
at com.sun.ejb.containers.EJBContainerTransactionManager.checkExceptionClientTx(EJBContainerTransactionManager.java:662)
at com.sun.ejb.containers.EJBContainerTransactionManager.postInvokeTx(EJBContainerTransactionManager.java:507)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4566)
......... (and so on....)
at com.me.MessageBeans.MessageReceiver.doStuff(MessageReceiver.java:86)
at com.me.MessageBeans.MessageReceiver.onMessage(MessageReceiver.java:61)
at sun.reflect.GeneratedMethodAccessor313.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1081)
at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1153)
at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:4786)
at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:656)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:822)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:608)
at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:55)
at org.jboss.weld.ejb.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:52)
at sun.reflect.GeneratedMethodAccessor310.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:883)
......... (and so on....)
Caused by: javax.validation.ConstraintViolationException: Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'prePersist'. Please refer to embedded ConstraintViolations for details.
// I try to persist myObject with JPA into the database (that's what's not working right now.. but it's beside the point here
......... (and so on....)
JMS Queue
to redeliver messages (that cause any Exceptions
or could not be delivered successfully for any other reason) ? (e.g catching the exceptions, setting some parameters when sending the message...)
Is there a parameter/option I have to set in GlassFish when setting up the DestinationResources or ConnectionFactories ?
And how could I clear the Queue manually, because right now it's full with "redeliver messages" and every time I deploy my application I get flooded with log messages within minutes.
Thank you all for your time and for reading :)
Transaction management in MDBs is tricky.
What is happening is that a java.lang.RuntimeException
is being thrown from your JPA Facade service method and this automatically marks the current transaction for rollback. Therefore it's already too late by the time it reaches the catch
clause in your MDB. JMS will retry failed transactions.
Any java.lang.RuntimeException
escaping from your service method will mark the MDB's transaction for rollback. You prevent this by catching it in the service method.
You may need to annotate the service method in your JPA Facade with @ TransactionAttribute(REQUIRES_NEW) in case JPA marks the Tx (not sure about that) or another EJB call from within the service method fails.
You can follow the instructions at To Purge Messages From a Physical Destination to clear your queue.