需要帮助以两种方式处理MDB异常

时间:2013-05-02 16:57:16

标签: jms jboss-mdb

我正在尝试在处理邮件时处理两种不同类型的问题。

第一个问题是远程数据库是否已关闭。在这种情况下,邮件应该停止处理,稍后再试。此消息永远不应该转到DLQ,并应继续尝试,直到远程数据库启动。

第二个问题是邮件出现问题。在这种情况下,它应该转到DLQ。

我应该如何构建以下代码?

@Override
public void onMessage(Message message) {
    try {

    // Do some processing
    messageProcessing(message);  // Should DLQ if message is bad

    // Save to the database
    putNamedLocation(message);  // <<--- Exception when external DB is down

    } catch (Exception e) {
        logger.error(e.getMessage());
        mdc.setRollbackOnly();
    }
}

1 个答案:

答案 0 :(得分:0)

假设您可以在MDB的代码主体中明确地检测到错误消息,我会直接将错误消息写入DLQ。这使您可以更自由地对错误进行分类,并可选择将不同类型的错误消息发送到不同的“DLQ-Like”队列,和/或将生存时间应用于DLQ消息,以便不希望 - 正在处理的类型消息永远不会堆积在队列中。您可以将@Resource带注释的实例变量添加到引用ConnectionFactory和Queue引用的MDB类,以支持将消息发送到目标DLQ。最重要的是,确保您自己检测到错误和DLQ消息。

对于数据库关闭,您可以通过在获取连接或编写更新时捕获异常来检测此问题。在这种情况下,清理资源并抛出RuntimeException。这将导致重新传递消息,但您需要检查JMS配置以获取两件事:

  1. 确保最大重新传送计数足够高,否则计数将勾选,最终消息将最终为DLQ。
  2. 如果您的JMS实现支持它,请为被拒绝的消息添加重新传递延迟,以便让DB有一段时间重新启动,否则您的消息将无休止地在传递/拒绝循环中旋转。
  3. 为了避免#2(如果您的JMS实现不支持redilvery延迟,如WebSphereMQ,这很棘手),您可以使用JBoss JMX管理接口让MDB在MDB上停止(以及稍后重新启动)传递。但是,您不能在处理消息的同一个线程中的MDB内部执行此操作,因为MDB将等待消息完成处理,而它不能因为它正在等待MDB停止,它可以因为... [等等]所以...你最好的选择是启动某种轮询DB的哨兵,当它找到它时,停止MDB,当它再次找到它时,重新启动它。有关如何执行该操作的摘要,请参阅此question

    最后一部分应该有助于处理消息验证导致的任何意外异常。 (即数据库很好,但由于某种原因,该消息完全是fubar导致未捕获的异常导致重新传递消息)。由于down-DB消息不应该被重新传递超过几次(由于你的哨兵),你可以检查消息的重新传递计数,如果它是非常高的那么你知道你有毒药消息,你可以抛弃它,或DLQ它。

    希望这有帮助。