如果在使用消息后出现任何错误,如何在JMS Message Queue中保留消息?

时间:2015-05-15 18:43:12

标签: java jms message-queue middleware

我的方案是 - 我将消息发布到队列中,一旦消息消耗,我将其发送到第三方中间件应用程序。如果该中间件应用程序已关闭,那么我发布的消息就会消失。如果中间件应用程序关闭而我希望它处于保持状态或在队列中等待,我不想丢失该消息。请建议,如何处理这种情况?

4 个答案:

答案 0 :(得分:5)

您应该像这样创建会话:

Session session = connection.createSession(false,
                       Session.CLIENT_ACKNOWLEDGE);

当您尝试将消息发送到第三方应用时:

  • 如果它正常,你应该知道这条消息。

  • 如果它失败了你就不应该知道它,这样JMS提供者就可以重新发送它,并且消息不会丢失。 message.acknowledge();

另外,您可以看一下:JMS AUTO_ACKNOWLEDGE when is it acknowledged?

答案 1 :(得分:5)

JMS队列不是邮件存储。

如果你有一条错误消息"如果处理继续失败,那么JMS服务器(如果已配置)将不可避免地将该消息转储到“死消息队列”#34;这将慢慢填满,直到另一个进程耗尽它。

您不希望在队列中保留错误消息,因为它们可能会阻塞队列(假设您有10个消费者,前10条消息都是坏消息,所以所有进程都会继续连枷关于坏消息 - 拖延队列。)

因此,您需要一些机制将消息存储到异常接收器中,然后可以将它们注入主队列进行处理。

死信息队列不是这种机制(不要将消息存储在JMS队列中),而是可以将ROUTE异常消息路由到更永久的存储区域(即db表或其他东西)的机制

在那里,他们可以被审查(自动,手动,无论如何),并重新传递或取消。

但关键是你需要一个外部机制,仅JMS服务器并不适合这类消息。

答案 2 :(得分:4)

这可以通过我的会话确认来实现。为此,首先修改您的生产者代码以使用Session.AUTO_ACKNOWLEDGE。创建队列会话时,将AUTO_ACKNOWLEDGE设为false。这意味着消费者必须承认。当消费者发送消息确认时,消息将从队列中删除,否则它将保留在队列中。

以下是生产者代码。

try {
        QueueConnectionFactory qcf = AppUtils.getQueueConnectionFactory(); 
        Queue q = AppUtils.getDestination();
        QueueConnection qConnection = qcf.createQueueConnection();
        QueueSession qSession = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

        QueueSender qSender = qSession.createSender(q);

        qConnection.start();
        TextMessage msg = qSession.createTextMessage("Hello");
        qSender.send(msg);

        qSender.close();
        qConnection.close();

    } catch (JMSException e) {
        // log your error to log file
        e.printStackTrace();
    }

在消费者方面,你必须做同样的事情,用AUTO_ACKNOWLEDGE创建一个队列会话为假。

处理完邮件后,您可以发送确认以从队列中删除邮件,否则邮件将保留在队列中。

try {
        QueueConnectionFactory qcf = getQueueConnectionFactory(); 
        Queue q = getDestination();
        QueueConnection qConnection = qcf.createQueueConnection();
        QueueSession qSession = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

        QueueReceiver qReceiver = qSession.createReceiver(q);

        qConnection.start();
        Message msg = qReceiver.receive();

  // here send your message to third party application 
  //if your third party application is down 
        if(thirdpartyapp is down){
          //here you can raise an exception 
          //or just do nothing 
          // you're not sending acknowledgement here so the msg will 
           //remain in the queue
        }else{      
          msg.acknowledge();//here youre sending ack, so msg will be deleted
          qReceiver.close();
          qConnection.close();
        }

    } catch (JMSException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

答案 3 :(得分:0)

虽然目前还不是很清楚你的应用程序是如何设计的,但我建议你修改消费者应用程序来消费本地事务中的消息并将消息发布到第三方中间件应用程序。如果post成功,那么您可以提交将从JMS队列中删除消息的事务。如果您的应用程序无法发布消息,您可以简单地回滚事务,这将使消息重新出现在JMS队列中。该消息将再次发送。