Reputation: 1083
What is the proper way, or the popular convention of deciding when to kill a listener? I can't seem to find a solid answer really anywhere. The queues I'm dealing with are IBM's MQ Queues, and I know typically that you would read until you receive a 2033 error code (my company does this in other applications) at which point you can wrap up, but for a SpringBoot Jms application what's the convention here? Once the queue is empty the listener just hangs until more messages come. I know HOW to kill it if I want, but how can I know WHEN?
As an example, here is a config for a sample project I threw together
@Configuration
@EnableTransactionManagement
public class JmsConfig {
@Bean
protected DefaultJmsListenerContainerFactory defaultJmsListenerContainerFactory() throws JMSException {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(mqQueueConnectionFactory());
factory.setConcurrency("1");
factory.setSessionTransacted(true);
factory.setAutoStartup(true);
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
factory.setErrorHandler(new JmsErrorHandler());
return factory;
}
@Bean
public MQQueueConnectionFactory mqQueueConnectionFactory() {
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
mqQueueConnectionFactory.setHostName(host);
try {
mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
mqQueueConnectionFactory.setCCSID(1208);
mqQueueConnectionFactory.setChannel(channel);
mqQueueConnectionFactory.setPort(port);
mqQueueConnectionFactory.setQueueManager(queueManager);
} catch (Exception e) {
e.printStackTrace();
}
return mqQueueConnectionFactory;
}
and here is the listener
@Component
public class Consumer {
@JmsListener(id = "myQueue", destination = "queue")
public void processMessage(Message message) throws MQException, IOException {
try {
String messageString = ((TextMessage) message).getText();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
Besides the main class and the ErrorHandler, that is literally the whole sample project, and it will process messages. What I have done in other applications is instantiated a MQQueue
given the queue values and just simple did queue.getCurrentDepth()
and if I get a zero I then call on an instance of a ListenerContainerController that then calls stop from a JmsListenerEndpointRegistry given the queues id.
Does Spring have an easy way of communication "hey your queue is now empty" or is there a way to end it after x amount of time has passed?
Upvotes: 4
Views: 2291
Reputation: 124441
A JmsListener
is intended to receive and process messages as they arrive on the destination. It isn't intended to read until the destination is empty and then stop, it is designed to keep running.
Instead just use a JmsTemplate
and its receive
method to read the messages until they are done. Then process them and write a report.
Ultimately you could even create a Spring Batch job using the JmsItemReader
, this reader will read until there is nothing more to read and then it will all end. Underneath it also uses a JmsTemplate
What you could do then is, as you are using Spring Boot, use a cron job to daily trigger this job (which is basically done launching the jar you created). See also the reference guide of Spring Boot on how to work with batch applications.
Upvotes: 3