捕获消息驱动Bean(MDB)中的异常(Catch Exceptions inside a Message Driven Bean (MDB))

编程入门 行业动态 更新时间:2024-10-17 02:55:57
捕获消息驱动Bean(MDB)中的异常(Catch Exceptions inside a Message Driven Bean (MDB))

我该如何处理mdb中的异常? 我有一种有趣的感觉,异常发生在try catch块之后,所以我无法捕获并记录它。 Glassfish v3决定重复整个信息。 它运行到一个无限循环,并在硬盘上写入很多日志文件。

我正在使用Glassfishv3.01 + Eclipselink 2.0.1

public class SaveAdMessageDrivenBean implements MessageListener { @PersistenceContext(unitName="QIS") private EntityManager em; @Resource private MessageDrivenContext mdc; public void onMessage(Message message) { try { if (message instanceof ObjectMessage) { ObjectMessage obj = (ObjectMessage)message; AnalyzerResult alyzres = (AnalyzerResult)obj.getObject(); save(alyzres); } } catch (Throwable e) { mdc.setRollbackOnly(); log.log(Level.SEVERE, e); } } @TransactionAttribute(TransactionAttributeType.REQUIRED) private void save(AnalyzerResult alyzres) throws PrdItemNotFoundException { Some s = em.find(Some.class, somepk); s.setSomeField("newvalue"); // SQL Exception happens after leaving this method because of missing field for ex. } }

How must I handle exceptions inside a mdb? I have the funny feeling that the exception happens after the try catch block so I'm not able to catch and log it. Glassfish v3 decides to repeat the whole message. It runns into a infinite loop and writes lot's of logfiles on the harddrive.

I'm using Glassfishv3.01 + Eclipselink 2.0.1

public class SaveAdMessageDrivenBean implements MessageListener { @PersistenceContext(unitName="QIS") private EntityManager em; @Resource private MessageDrivenContext mdc; public void onMessage(Message message) { try { if (message instanceof ObjectMessage) { ObjectMessage obj = (ObjectMessage)message; AnalyzerResult alyzres = (AnalyzerResult)obj.getObject(); save(alyzres); } } catch (Throwable e) { mdc.setRollbackOnly(); log.log(Level.SEVERE, e); } } @TransactionAttribute(TransactionAttributeType.REQUIRED) private void save(AnalyzerResult alyzres) throws PrdItemNotFoundException { Some s = em.find(Some.class, somepk); s.setSomeField("newvalue"); // SQL Exception happens after leaving this method because of missing field for ex. } }

最满意答案

你有一个消息中毒的坏情况......

我看到的主要问题是:

你在onMessage()直接调用save()方法:这意味着容器没有办法在save方法周围注入正确的事务处理代理 在任何情况下, save()方法都应该有@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)以便在单独的事务中提交,否则它将加入onMessage事务(默认为REQUIRED )并绕过你的异常处理代码,beign后提交成功执行onMessage

我要做的是:

将save方法移动到新的无状态会话Bean:

@Stateless public class AnalyzerResultSaver { @PersistenceContext(unitName="QIS") private EntityManager em; @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) private void save(AnalyzerResult alyzres) throws PrdItemNotFoundException { Some s = em.find(Some.class, somepk); s.setSomeField("newvalue"); // SQL Exception happens after leaving this method } }

在MDB中注入此bean:

public class SaveAdMessageDrivenBean implements MessageListener { @Inject private AnalyzerResultSaver saver; @Resource private MessageDrivenContext mdc; public void onMessage(Message message) { try { if (message instanceof ObjectMessage) { ObjectMessage obj = (ObjectMessage)message; AnalyzerResult alyzres = (AnalyzerResult)obj.getObject(); saver.save(alyzres); } } catch (Throwable e) { mdc.setRollbackOnly(); log.log(Level.SEVERE, e); } } }

另一个提示:在此代码中,消息中毒仍然存在。 现在它派生自调用mdc.setRollbackOnly();的行mdc.setRollbackOnly(); 。

我建议在这里记录异常并将消息传递到毒性队列,从而阻止容器无限制地重新提交消息。

更新:

“毒性队列”或“错误队列”只是保证您的(希望可恢复的)丢弃的消息不会完全丢失的一种手段。 它在集成场景中被大量使用,其中无法保证消息数据的正确性。

设置中毒队列意味着定义目标队列或主题,并将“错误”消息重新发送到此目标。

操作员应定期检查此队列(通过专用应用程序)并修改消息并重新提交到“正常”队列,或丢弃该消息并要求重新发送。

You got a bad case of message poisoning...

The main issues I see are that:

you are calling directly the save() method in your onMessage(): this means thet the container has no way to inject the proper transaction handling proxy around the save method in any case the save() method should have @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) in order to commit in a separate transaction, otherwise it will join the onMessage transaction (which default to REQUIRED) and bypass your exception handling code, beign committed after the successful execution of onMessage

What I woud do is:

Move the save method to a new Stateless session bean:

@Stateless public class AnalyzerResultSaver { @PersistenceContext(unitName="QIS") private EntityManager em; @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) private void save(AnalyzerResult alyzres) throws PrdItemNotFoundException { Some s = em.find(Some.class, somepk); s.setSomeField("newvalue"); // SQL Exception happens after leaving this method } }

Inject this bean in your MDB:

public class SaveAdMessageDrivenBean implements MessageListener { @Inject private AnalyzerResultSaver saver; @Resource private MessageDrivenContext mdc; public void onMessage(Message message) { try { if (message instanceof ObjectMessage) { ObjectMessage obj = (ObjectMessage)message; AnalyzerResult alyzres = (AnalyzerResult)obj.getObject(); saver.save(alyzres); } } catch (Throwable e) { mdc.setRollbackOnly(); log.log(Level.SEVERE, e); } } }

Another tip: in this code the message poisoning still exists. Now it derives from the line invoking mdc.setRollbackOnly();.

I'd suggest here to log the exception and transfer the message to a poison queue, thus preventing the container to resubmit the message ad infinitum.

UPDATE:

A 'poison queue' or 'error queue' is simply a mean to guarantee that your (hopefully recoverable) discarded messages will not be completely lost. It is used heavily in integration scenarios, where the correctness of the message data is not guaranteed.

Setting up a poison queue implies defining a destination queue or topic and redeliver the 'bad' messages to this destination.

Periodically, an operator should inspect this queue (via a dedicated application) and either modify the messages and resubmit to the 'good' queue, or discard the message and ask for a resumbit.

更多推荐

本文发布于:2023-07-04 17:09:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1026963.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:异常   消息   MDB   Bean   Driven

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!