【问题标题】:How do I delay JMS Message sending?如何延迟 JMS 消息发送?
【发布时间】:2014-02-15 17:39:44
【问题描述】:

如何延迟 JMS 消息发送或继续不确定时间?

我用的是Weblogic,如你所知,JMS发送后,接收方会异步处理消息,但是,此时或有时外部资源还没有为接收方准备好,所以,我想有一些检查逻辑延迟发送或处理消息。我猜例如:我将消息放入待处理队列,然后经常检查资源可用性,一旦发送或继续消息?

大家知道Weblogic是否支持这个或者如何实现它?

【问题讨论】:

  • 我在 weblogic 中没有听说过这样的事情。在我看来,您必须自己实现 waiting 队列。
  • JMS 的目的是将消息放到队列中,让接收者异步处理。那么,您能否解释一下“接收方必须立即采取行动”的意​​思?
  • 感谢重播,只是把问题修改得更清楚一点。

标签: java jakarta-ee jms


【解决方案1】:

您是否查看过 WebLogic 服务器中配置的 JMS 对象的交付时间设置?

Oracle WebLogic docs

【讨论】:

    【解决方案2】:

    通常要延迟接收消息直到资源准备好,不会调用 connection.start() 方法。逻辑如下:

    1. 接收器启动并建立连接并设置所有 JMS 资源。
    2. connection.start() 未被调用。
    3. 等待其他资源初始化
    4. 使用 connection.start() 启动 JMs 连接

    您甚至可以使用此方法暂停消息侦听器接收的消息。这种技术在使用 JMS 的 GUI 工具中非常常见。

    【讨论】:

    • 谢谢,你能告诉我如何暂停接收消息吗?
    • Connection.start() 和 Connection.stop() 可以在消息侦听器线程之外调用。在程序停止调用connection.stop()之前它很常见。要在任何时间暂停接收消息,您可以调用 connection.stop()
    【解决方案3】:

    您完全可以在 JMS 中执行此操作,只需使用本地队列来存储消息即可;当接收器可用时发送到远程队列。

    选项 1(理想、安全)

    1) 首先,在WebLogic中创建一个JMS Server,LocalJMSServer

    2) 确保仅将此资源定位到本地 WebLogic 实例。

    3) 为LocalJMSServer 创建一个队列tempQueue

    4) 您的应用程序总是向tempQueue 发送消息。由于该队列是本地队列,因此消息仅位于队列中,并且它们也被持久化,这在服务器崩溃时非常有用。

    5) 您需要在 WebLogic 中进行单独的 JMSServer 配置来托管 remoteQueue,因为该队列将针对远程 WebLogic 实例。

    6) 您的应用程序会定期检查远程接收器的可用性:

       if( receiverIsAvailable()){
        ...
       }
    

    ...当接收者可用时,将来自tempQueue 的消息出列并发送到remoteQueue...

    Queue tempQueue = (Queue) ctx.lookup("tempQueue");
    QueueSession queueLocalSession = 
      queueConn.createQueueSession(false,
         Session.CLIENT_ACKNOWLEDGE);  
    QueueReceiver queueReceiver = queueLocalSession.createReceiver(tempQueue);
    TextMessage localMessage = (TextMessage) queueReceiver.receive();
    
    //send to remote queue
    Queue remoteQueue = (Queue) ctx.lookup("remoteQueue");
    QueueSender queueSender = queueRemoteSession.createSender(remoteQueue);
    Message newMessage = queueRemoteSession.createTextMessage(
      localMessage.getText());
    queueSender.send( newMessage);
    
    //now acknowledge the message since we safely sent to remoteQueue
    localMessage.acknowledge(); 
    

    我喜欢这种方法,因为它完全是事务性的;如果出现任何问题,只要您使用 PERSISTENT 模式,您就不会丢失消息。另外,从tempQueue拉取消息时,必须使用同步接收器(如上),不能使用onMessage(),因为它会立即处理来自本地队列的消息。

    选项 2(更简单,更不安全)

    您也可以使用内存队列(不是 JMS )在本地存储消息内容:

    ArrayBlockingQueue queue = new ArrayBlockingQueue<String>();
    queue.add(messageContents1);
    queue.add(messageContents2);
    ...
    

    您的应用程序在接收端检查资源可用性,如果可用,则立即出列并立即发送真正的 JMS 消息:

    if( receiverIsAvailable()){
       while(!queue.isEmpty()){
          Message message = session.createTextMessage();
          message.setText(queue.take());
          queueSender.send(message);
       }
    }
    

    这种方法的问题是存储在queue 中的消息驻留在内存中;如果发件人崩溃,您将丢失这些消息。

    希望对你有帮助!

    【讨论】:

      【解决方案4】:

      如果外部资源没有准备好,你可以让你的接收器阻塞。由于接收者“忙”,因此在队列被阻塞时不会再从队列中拉出消息。

      【讨论】:

        【解决方案5】:

        假设您使用 Websphere MQ,我认为它不受支持。

        JMS 2.0 确实支持延迟传递[1] 消息,但没有更多信息就很难回答。

        [1]https://java.net/projects/jms-spec/pages/JMS20FinalRelease#What_s_new_in_JMS_2.0?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-07-18
          • 1970-01-01
          • 2014-09-27
          • 2011-03-27
          • 1970-01-01
          • 2014-08-01
          • 2012-05-08
          相关资源
          最近更新 更多