在 MessageDrivenBean 中将事务标记为仅回滚,而不重试消息
我有以下 MessageDrivenBean:
@MessageDriven(mappedName = "jms/...", activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "endpointExceptionRedeliveryAttempts", propertyValue = "5"),
@ActivationConfigProperty(propertyName = "endpointExceptionRedeliveryInterval", propertyValue = "1000")
})
public class MyMessageListener implements MessageListener {
@Resource
private MessageDrivenContext context;
@Override
@TransactionAttribute(REQUIRED)
public void onMessage(Message message) {
}
}
在 onMessage
方法中,我做了一些处理,这在这里并不重要。在某些情况下,我想放弃处理。在这种情况下,我想将事务标记为仅回滚,并且不想重试处理。
至少在 Glassfish 3.1.1 上,如果我在 MessageDrivenContext
上调用 context.setRollbackOnly()
并结束处理而不引发异常,则消息会以非常、间隔很短。所以这对我来说是没有选择的。
如果我抛出 RuntimeException ,消息将按照我指定的方式重新传递。重发5次,间隔1秒。但就我而言,我根本不想重试处理。
如果我只是简单地结束处理而不引发任何异常,并且不调用 context.setRollbackOnly(),那么事务就会如人们所期望的那样被提交。但我需要回滚事务,因为我可能已经更改了一些 JPA 实体。
我的问题是:如何将事务标记为仅回滚而不触发消息重新传递?
I have the following MessageDrivenBean:
@MessageDriven(mappedName = "jms/...", activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "endpointExceptionRedeliveryAttempts", propertyValue = "5"),
@ActivationConfigProperty(propertyName = "endpointExceptionRedeliveryInterval", propertyValue = "1000")
})
public class MyMessageListener implements MessageListener {
@Resource
private MessageDrivenContext context;
@Override
@TransactionAttribute(REQUIRED)
public void onMessage(Message message) {
}
}
Inside the onMessage
method, I do some processing which is not important here. In certain situations, I want to give up on the processing. In that situations I want to mark the transaction as rollback-only and don't want to retry the processing.
At least on Glassfish 3.1.1, if I call context.setRollbackOnly()
on the MessageDrivenContext
and end the processing without throwing an exception, the message is redelivered infinitely in very, very short intervals. So that is no option for me.
If I throw a RuntimeException
the message is redelivered as I have specified it. It is redelivered 5 times with 1 second interval. But in my case, I don't want to retry the processing at all.
If I simply end the processing without throwing any exception and without calling context.setRollbackOnly()
, the transaction is commited, as one would expect. But I need to rollback the transaction because I may have already altered some JPA entities.
The question I have is: How can I mark the transaction as rollback-only without triggering a message redelivery?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我看到两个选项:
getJMSRedelivered()
标志,然后简单地丢弃重新传递的消息。这里的问题是,在重新交付时,您不知道是否应该忽略重新交付(您说过在某些情况下您确实想重试处理)——您必须临时存储(在数据库或缓存中)ID处理失败的消息,以便您知道是否可以安全地忽略它们。I see two options:
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
, use bean-managed transaction and no AUTO_ACKNOWLEDGE (acknowledge the message explicitly in the MDB). Not an option if your MDB is a part of a larger XA transaction, you won't have a chance to influence the global transaction result.getJMSRedelivered()
flag on message and simply discard the redelivered message. The trouble here is, upon redelivery you don't know if it's a redelivery that you should ignore (you said in some cases you do want to retry processing) — you'd have to store temporarily (in a database, or cache) ids of messages that failed processing, so you know if you may ignore them safely.