I am using JMS with Spring's JmsListener. I am able to consume messages from a JMS queue, but it is using AUTO_ACKNOWLEDGE
. How can I set CLIENT_ACKNOWLEDGE
so that I can consume the other message only after that acknowledgment.
@Bean
public JmsListenerContainerFactory myFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setErrorHandler(t -> {
logger.info("An error has occurred in the transaction");
logger.error(t.getCause().getMessage());
});
configurer.configure(factory, connectionFactory);
factory.setConcurrency("4");
// You could still override some of Boot's default if necessary.
return factory;
}
@Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
@JmsListener(destination = "QUEUE_1", containerFactory = "myFactory", concurrency = "2")
public void receiveImgGenerationMessage(String transaction) {
logger.info("message received in queue " + transaction);
//I will call other api to process the message and do some operation
//after the message is processed
//I have to Acknowledge the message is processed
//so that i can consume the other message for process.
}
// jmsTemplate bean
public void sendmessage() {
for (int i =0 ; i < 10 ; < i++) {
jmsTemplate.convertAndSend("QUEUE_1", i);
}
}
You should use the setSessionAcknowledgeMode
method on your
org.springframework.jms.config.DefaultJmsListenerContainerFactory
instance to set CLIENT_ACKNOWLEDGE
mode, e.g.:
@Bean
public JmsListenerContainerFactory myFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setErrorHandler(t -> {
logger.info("An error has occurred in the transaction");
logger.error(t.getCause().getMessage());
});
factory.setSessionAcknowledgeMode(javax.jms.Session.CLIENT_ACKNOWLEDGE);
configurer.configure(factory, connectionFactory);
factory.setConcurrency("4");
// You could still override some of Boot's default if necessary.
return factory;
}
This is discussed in the Spring JMS JavaDoc:
The listener container offers the following message acknowledgment options:
"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default): This mode is container-dependent: For
DefaultMessageListenerContainer
, it means automatic message acknowledgment before listener execution, with no redelivery in case of an exception and no redelivery in case of other listener execution interruptions either. ForSimpleMessageListenerContainer
, it means automatic message acknowledgment after listener execution, with no redelivery in case of a user exception thrown but potential redelivery in case of the JVM dying during listener execution. In order to consistently arrange for redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or - preferably - setting "sessionTransacted" to "true" instead."sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE": Lazy message acknowledgment during (
DefaultMessageListenerContainer
) or shortly after (SimpleMessageListenerContainer
) listener execution; no redelivery in case of a user exception thrown but potential redelivery in case of the JVM dying during listener execution. In order to consistently arrange for redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or - preferably - setting "sessionTransacted" to "true" instead."sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE": Automatic message acknowledgment after successful listener execution; best-effort redelivery in case of a user exception thrown as well as in case of other listener execution interruptions (such as the JVM dying).
"sessionTransacted" set to "true": Transactional acknowledgment after successful listener execution; guaranteed redelivery in case of a user exception thrown as well as in case of other listener execution interruptions (such as the JVM dying).
You could also use this in your Spring Boot application.properties
:
spring.jms.listener.acknowledge-mode=CLIENT