1

我在处理消息时尝试处理两种不同类型的问题。

第一个问题是远程数据库是否关闭。在这种情况下,消息应该停止处理,然后再试一次。此消息不应该发送到 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();
    }
}
4

1 回答 1

0

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

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

  1. 确保 max-redelivery 计数足够高,否则计数将结束并且消息最终将被 DLQed。
  2. 如果您的 JMS 实现支持它,请为被拒绝的消息添加重新传递延迟,以允许数据库有时间恢复,否则您的消息将在传递/拒绝循环中无休止地旋转。

为了避免 #2(如果您的 JMS 实现不支持 redilvery 延迟,如 WebSphereMQ,这很棘手),您可以使用 MDB 的 JBoss JMX 管理接口来停止(然后重新启动)MDB 上的交付。但是,您不能在处理消息的同一线程中的 MDB 内执行此操作,因为 MDB 将等待消息完成处理,但它不能这样做,因为它正在等待 MDB 停止,它可以'不是因为...... [等等] 所以......你最好的选择是启动某种轮询数据库的哨兵,当它找到它时,停止 MDB,当它再次找到它时,重新启动它。有关如何执行此操作的片段,请参阅此问题。

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

希望这会有所帮助。

于 2013-05-02T20:57:52.387 回答