Spring JMS(ActiveMQ) delayed delivery of messages

17,870

Solution 1

The comments give the answer. By default scheduled message support is disabled. You must enabled it in the broker XML configuration file as mentioned on the documentation page.

An example Broker tag with scheduler support enabled:

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}" schedulerSupport="true">

You must of course restart the broker in order for configuration changes to take affect. Then when you send a message you need to add the JMS headers that tell the broker what type of delay you want.

message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, scheduledDelay);

Solution 2

Two things needs to be done to resolve this.

  • By default scheduled message support is disabled. We must enabled it in the broker XML configuration file.

broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}" schedulerSupport="true">

  • Set the delay before sending the message.

    public void send(Object object) {
        log.info("put <" + object + ">");
        jmsTemplate.convertAndSend(QUEUE_NAME, object, m -> {
           m.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, 10000);
           return m;
        });
    }
    
Share:
17,870
Ayelet
Author by

Ayelet

Updated on June 26, 2022

Comments

  • Ayelet
    Ayelet almost 2 years

    We're trying to set a delay on some JMS messages, so that a message will only be added to the queue/ received by the listener after x time. So far we've tried 2 approaches that didn't work.

    1) According to the spring documentation, we can set the delivery delay on the JMSTemplate. This is the sample code we tried:

    @Autowired
    private JmsTemplate jmsTemplate;
    
    ...
    long deliveryDelay = ...;
    this.jmsTemplate.setDeliveryDelay(deliveryDelay);
    this.jmsTemplate.convertAndSend(
                        queue.getName(),
                        event);
    ...
    

    However, we get the following exception, even though our spring jms version is 4.0.5:

    java.lang.IllegalStateException: setDeliveryDelay requires JMS 2.0
    

    2) We also tried setting the delay on the message itself, but it looks like the delay was ignored, and the message was delivered immediately anyway.

    @Component
    public class MyMessageConverter implements MessageConverter {
    
    ...
    
    @Override
    public Message toMessage(Object eventObject, Session session) throws JMSException, MessageConversionException {
    
    ...
    long deliveryDelay = ...;
    objectMessage.setLongProperty(
                      ScheduledMessage.AMQ_SCHEDULED_DELAY,
                      deliveryDelay);
    return objectMessage;
    }
    }
    

    The jmsTemplate definition in the spring xml:

    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="cachingConnectionFactory" />
        <property name="messageConverter" ref="myMessageConverter" />
        <property name="sessionTransacted" value="true" />
    </bean>
    

    Does anyone has any suggestions on what the problems are / other ideas on how to achieve delayed messaging? Thanks!

    • M. Deinum
      M. Deinum almost 10 years
      Your first approach will only work for JMS 2.0 compliant JMS brokers, ActiveMQ isn't (at the moment) one of them. The second option is only going to work if you also enabled scheduling on the JMS broker side else the property will do nothing.
    • Ayelet
      Ayelet almost 10 years
      Thanks @M.Deinum. I set schedulerSupport="true" in the activemq.xml and now it works.
    • znlyj
      znlyj about 9 years
      The delayed message is stored in the client side?
  • Tim Bish
    Tim Bish over 8 years
    This actually depends on what broker version you are using, later releases do have an in memory scheduler store for brokers that run without persistence.
  • mech
    mech over 6 years
    Could you explain how this code snippet answers the question?
  • Melebius
    Melebius over 6 years
    Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you’ve made.
  • Tan
    Tan almost 4 years
    Hey ,@Tim Bish! I am wondering where should I define this line to enable scheduler support <broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}" schedulerSupport="true">. I checked the documentation you shared and it doesn't says anything. My inclination is conf/activem/xml, however, I couldn't find anything related to enabling schedulerSupport over there. Thanks !
  • Tan
    Tan almost 4 years
    Could you tell me where in conf/activemq.xml, I should define this line ? <broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}" schedulerSupport="true">