I want to implement publisher confirms functionality into my code, gone through the http://www.rabbitmq.com/blog/2011/02/10/introducing-publisher-confirms/ but was unable to understand
I am using QueueBuilder as follows
#Bean
public Queue salesQueue() {
return QueueBuilder.durable(salesQueue)
.withArgument("x-max-length", 1)
.withArgument("x-overflow", "reject-publish")
.build();
}
RabbitTemplate creation
#Bean
public AmqpTemplate rabbitTemplate(ConnectionFactory connectionFactory)
{
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(jsonMessageConverter());
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
System.out.println("Message with correlation ID {} confirmed by
broker."+ correlationData.getId());
} else {
System.out.println("Broker is unable to handle message with
correlation ID {} : {}"+correlationData.getId()+","+
cause);
}
});
return rabbitTemplate;
}
sending message to queue
#Service
public class RabbitMQSender {
private static long sentMessageCount =0L;
#Autowired
private AmqpTemplate rabbitTemplate;
#Value("${rabbitmq.queue}")
String queueName;
public void send() {
long x=++sentMessageCount;
rabbitTemplate.convertAndSend(queueName,"
{'empId':'"+x+"','empName':'YYYYYY'}");
}
Presently I have set the queue length as 1, whenever I send messages greater than 1, I am expecting it to inform publisher about rejection of message via a basic.nack message which is not happening...
I request you to help me with this
Thank you
Related
We have an order managament system in which after every order state update we make an api call to our client to keep them updated. We do this by first sending a message to a sqs queue and inside a consumer we hit our clients api. The processing on consumer side usually takes about 300-350ms but The approximate age of oldest message in sqs dashboard is showing spikes that reach upto 50-60 secs.
Seeing this I thought that maybe one consumer is not enough for our load and I created multiple DMLC beans and multiple copies of our consumer class. I attached these consumer classes as listeners in these DMLCs. But I have not seen any improvement in approximate age of oldest message.
I am guessing that maybe only one of the DMLC is processing these messages and others are just sitting idle.
I added multiple DMLCs because there are other places in pur codebase where the same thing is used, But now I am not sure if this is the correct way to solve the problem.
My Consumer class looks like this:
#Component
#Slf4j
#RequiredArgsConstructor
public class HOAEventsOMSConsumer extends ConsumerCommon implements MessageListener {
private static final int MAX_RETRY_LIMIT = 3;
private final OMSEventsWrapper omsEventsWrapper;
#Override
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
String jmsMessageId = textMessage.getJMSMessageID();
ConsumerLogging.logStart(jmsMessageId);
String text = textMessage.getText();
log.info(
"Inside HOA Events consumer Request jmsMessageId:- " + jmsMessageId + " Text:- "
+ text);
processAndAcknowledge(message, text, textMessage);
} catch (JMSException e) {
log.error("JMS Exception while processing surge message", e);
}
}
private void processAndAcknowledge(Message message, String text, TextMessage textMessage) throws JMSException {
try {
TrimmedHOAEvent hoaEvent = JsonHelper.convertFromJsonPro(text, TrimmedHOAEvent.class);
if (hoaEvent == null) {
throw new OMSValidationException("Empty message in hoa events queue");
}
EventType event = EventType.fromString(textMessage.getStringProperty("eventType"));
omsEventsWrapper.handleOmsEvent(event,hoaEvent);
acknowledgeMessage(message);
} catch (Exception e) {
int retryCount = message.getIntProperty("JMSXDeliveryCount");
log.info("Retrying... retryCount: {}, HOAEventsOMSConsumer: {}", retryCount, text);
if (retryCount > MAX_RETRY_LIMIT) {
log.info("about to acknowledge the message since it has exceeded maximum retry limit");
acknowledgeMessage(message);
}
}
}
}
And my DMLC configuration class looks like this:
#Configuration
#SuppressWarnings("unused")
public class HOAEventsOMSJMSConfig extends JMSConfigCommon{
private Boolean isSQSQueueEnabled;
#Autowired
private HOAEventsOMSConsumer hoaEventsOMSConsumer;
#Autowired
private HOAEventsOMSConsumer2 hoaEventsOMSConsumer2;
#Autowired
private HOAEventsOMSConsumer3 hoaEventsOMSConsumer3;
#Autowired
private HOAEventsOMSConsumer4 hoaEventsOMSConsumer4;
#Autowired
private HOAEventsOMSConsumer5 hoaEventsOMSConsumer5;
#Autowired
private HOAEventsOMSConsumer6 hoaEventsOMSConsumer6;
#Autowired
private HOAEventsOMSConsumer7 hoaEventsOMSConsumer7;
#Autowired
private HOAEventsOMSConsumer8 hoaEventsOMSConsumer8;
#Autowired
private HOAEventsOMSConsumer9 hoaEventsOMSConsumer9;
#Autowired
private HOAEventsOMSConsumer10 hoaEventsOMSConsumer10;
public HOAEventsOMSJMSConfig(IPropertyService propertyService, Environment env) {
queueName = env.getProperty("aws.sqs.queue.oms.hoa.events.queue");
endpoint = env.getProperty("aws.sqs.queue.endpoint") + queueName;
JMSConfigCommon.accessId = env.getProperty("aws.sqs.access.id");
JMSConfigCommon.accessKey = env.getProperty("aws.sqs.access.key");
try {
ServerNameCache serverNameCache = CacheManager.getInstance().getCache(ServerNameCache.class);
if (serverNameCache == null) {
serverNameCache = new ServerNameCache();
serverNameCache.set(InetAddress.getLocalHost().getHostName());
CacheManager.getInstance().setCache(serverNameCache);
}
this.isSQSQueueEnabled = propertyService.isConsumerEnabled(serverNameCache.get(), false);
} catch (Exception e) {
this.isSQSQueueEnabled = false;
}
}
#Bean
public JmsTemplate omsHOAEventsJMSTemplate(){
SQSConnectionFactory sqsConnectionFactory;
if (endpoint.toLowerCase().contains("localhost")) {
sqsConnectionFactory =
SQSConnectionFactory.builder().withEndpoint(getEndpoint("sqs")).build();
} else {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(awsCredentialsProvider)
.withNumberOfMessagesToPrefetch(10)
.withEndpoint(endpoint)
.build();
}
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(sqsConnectionFactory);
JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
jmsTemplate.setDefaultDestinationName(queueName);
jmsTemplate.setDeliveryPersistent(false);
jmsTemplate.setSessionTransacted(false);
jmsTemplate.setSessionAcknowledgeMode(SQSSession.UNORDERED_ACKNOWLEDGE);
return jmsTemplate;
}
#Bean
public DefaultMessageListenerContainer jmsListenerHOAEventsListenerContainer() {
SQSConnectionFactory sqsConnectionFactory;
if (endpoint.toLowerCase().contains("localhost")) {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withEndpoint(getEndpoint("sqs"))
.build();
} else {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(awsCredentialsProvider)
.withNumberOfMessagesToPrefetch(10)
.withEndpoint(endpoint)
.build();
}
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setConnectionFactory(sqsConnectionFactory);
dmlc.setDestinationName(queueName);
dmlc.setAutoStartup(isSQSQueueEnabled);
dmlc.setMessageListener(hoaEventsOMSConsumer);
dmlc.setSessionTransacted(false);
dmlc.setSessionAcknowledgeMode(SQSSession.UNORDERED_ACKNOWLEDGE);
return dmlc;
}
#Bean
public DefaultMessageListenerContainer jmsListenerHOAEventsListenerContainerNo2() {
SQSConnectionFactory sqsConnectionFactory;
if (endpoint.toLowerCase().contains("localhost")) {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withEndpoint(getEndpoint("sqs"))
.build();
} else {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(awsCredentialsProvider)
.withNumberOfMessagesToPrefetch(10)
.withEndpoint(endpoint)
.build();
}
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setConnectionFactory(sqsConnectionFactory);
dmlc.setDestinationName(queueName);
dmlc.setAutoStartup(isSQSQueueEnabled);
dmlc.setMessageListener(hoaEventsOMSConsumer2);
dmlc.setSessionTransacted(false);
dmlc.setSessionAcknowledgeMode(SQSSession.UNORDERED_ACKNOWLEDGE);
return dmlc;
}
#Bean
public DefaultMessageListenerContainer jmsListenerHOAEventsListenerContainerNo3() {
SQSConnectionFactory sqsConnectionFactory;
if (endpoint.toLowerCase().contains("localhost")) {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withEndpoint(getEndpoint("sqs"))
.build();
} else {
sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(awsCredentialsProvider)
.withNumberOfMessagesToPrefetch(10)
.withEndpoint(endpoint)
.build();
}
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setConnectionFactory(sqsConnectionFactory);
dmlc.setDestinationName(queueName);
dmlc.setAutoStartup(isSQSQueueEnabled);
dmlc.setMessageListener(hoaEventsOMSConsumer3);
dmlc.setSessionTransacted(false);
dmlc.setSessionAcknowledgeMode(SQSSession.UNORDERED_ACKNOWLEDGE);
return dmlc;
}
}
If this question is already answered somehwere else, then please point me towards that.
I Started by setting up an interceptor for outgoing messages which is working smoothly, but
when i try to intercept incomming messages in the consumers, the postProcessMessage method
is skipped and the message reaches the method annotated with #RabbitListener, bellow is my code for the whole proccess, i ommited unimportant code.
Producer
RabbitMQProducerInterceptor
#Component
#Slf4j
public class RabbitMQProducerInterceptor implements MessagePostProcessor {
#Override
public Message postProcessMessage(Message message) throws AmqpException {
log.info("Getting the current HttpServletRequest");
HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
log.info("Extracting the X-REQUEST-ID from the header of the HttpServletRequest");
String XRequestId = req.getHeader(ShareableConstants.X_REQUEST_ID_HEADER);
log.info("Adding X-REQUEST-ID {} to the RabbitMQ Producer Header", XRequestId);
message.getMessageProperties().getHeaders().put(ShareableConstants.X_REQUEST_ID_HEADER, XRequestId);
return message;
}
}
RabbitMQProducerConfig
#Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setReplyTimeout(60000);
MessagePostProcessor[] processors = {new RabbitMQProducerInterceptor()};
rabbitTemplate.addBeforePublishPostProcessors(processors);
return rabbitTemplate;
}
Sending a message to the consumer
User Producer
public UserRegistrationResponseDTO register(UserRegistrationDTO userRegistrationDTO) {
log.info("Sending user registration request {}", userRegistrationDTO);
UserRegistrationDTO response = (UserRegistrationDTO) rabbitTemplate
.convertSendAndReceive(ShareableConstants.EXCHANGE_NAME,
ShareableConstants.CREATE_USER_ROUTING_KEY,
userRegistrationDTO);
return UserRegistrationResponseDTO.builder()
.username(response.getUsername())
.id(response.getId())
.createdAt(response.getCreatedAt()).build();
}
Consumer
RabbitMQConsumerConfig
#Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
MessagePostProcessor[] processors = {new RabbitMQConsumerInterceptor()};
rabbitTemplate.setAfterReceivePostProcessors(processors);
return rabbitTemplate;
}
RabbitMQConsumerInterceptor
#Component
public class RabbitMQConsumerInterceptor implements MessagePostProcessor {
#Override
public Message postProcessMessage(Message message) throws AmqpException {
String XRequestId = message.getMessageProperties().getHeader(ShareableConstants.X_REQUEST_ID_HEADER);
MDC.put(ShareableConstants.X_REQUEST_ID_HEADER, XRequestId);
return message;
}
}
User Consumer
#RabbitListener(bindings =
#QueueBinding(exchange = #Exchange(ShareableConstants.EXCHANGE_NAME),
key = ShareableConstants.CREATE_USER_ROUTING_KEY,
value = #Queue(ShareableConstants.USER_REGISTRATION_QUEUE_NAME)))
public UserRegistrationDTO receiveUser(UserRegistrationDTO userRegistrationDTO) {
log.info("receiving user {} to register ", userRegistrationDTO);
User user = Optional.of(userRegistrationDTO).map(User::new).get();
User createdUser = userService.register(user);
UserRegistrationDTO registrationDTO = UserRegistrationDTO.builder()
.id(createdUser.getId())
.username(createdUser.getUsername())
.createdAt(createdUser.getCreationDate())
.build();
return registrationDTO;
}
Here's the code, no exception is thrown, the only problem is the Interceptor being skipped
The RabbitTemplate is not used to receive messages for a #RabbitListener; messages are received by a listener container; you have to set the afterReceivePostProcessors on the listener container factory.
If you are using Spring Boot, just add the auto-configured SimpleRabbitListenerContainerFactory as a parameter to one of your other #Beans and set the MPP on it.
I have this RabbitMQ Spring Boot Configuration:
#Configuration
public class RabbitConfiguration {
// Main queue configuration
#Value("${rabbitmq.main.messages.queue}")
private String mainQueueName;
#Value("${rabbitmq.main.exchange.queue}")
private String mainExchangeName;
#Value("${rabbitmq.main.routing.key}")
private String mainRoutingKey;
// DLQ configuration
#Value("${rabbitmq.dlq.messages.queue}")
private String dlqQueueName;
#Value("${rabbitmq.dlq.exchange.queue}")
private String dlqExchangeName;
#Value("${rabbitmq.dlq.routing.key}")
private String dlqRoutingKey;
// Connectivity
#Value("${spring.rabbitmq.host}")
private String rabbitmqHost;
#Value("${spring.rabbitmq.port}")
private int rabbitmqPort;
#Value("${spring.rabbitmq.username}")
private String rabbitmqUsername;
#Value("${spring.rabbitmq.password}")
private String rabbitmqPassword;
// Not delivered messages, will be used eventually
#Value("${rabbitmq.not.delivered.messages.queue}")
private String notDeliveredMessagesQueue;
// status with delivered messages (callback default)
#Value("${rabbitmq.delivered.messages.queue}")
private String deliveredMessagesQueue;
#Bean
DirectExchange deadLetterExchange() {
return new DirectExchange(dlqExchangeName);
}
#Bean
DirectExchange exchange() {
return new DirectExchange(mainExchangeName);
}
#Bean
Queue dlq() {
return QueueBuilder.durable(dlqQueueName).build();
}
#Bean
Queue queue() {
return QueueBuilder
.durable(mainQueueName)
.withArgument("x-dead-letter-exchange", "deadLetterExchange")
.withArgument("x-dead-letter-routing-key", dlqQueueName).build();
}
#Bean
Binding deadLetterBinding() {
return BindingBuilder.bind(dlq()).to(deadLetterExchange()).with(dlqRoutingKey);
}
#Bean
Binding binding() {
return BindingBuilder.bind(queue()).to(exchange()).with(mainQueueName);
}
#Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
#Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(rabbitmqHost);
connectionFactory.setUsername(rabbitmqUsername);
connectionFactory.setPassword(rabbitmqPassword);
return connectionFactory;
}
#Bean
public RabbitAdmin rabbitAdmin() {
RabbitAdmin admin = new RabbitAdmin(connectionFactory());
admin.declareQueue(queue());
admin.declareExchange(exchange());
admin.declareBinding(binding());
return admin;
}
public AmqpTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(jsonMessageConverter());
return rabbitTemplate;
}
}
The problem is that when some exception is launched the message is not sent to DLQ queue.
Consumer:
#RabbitListener(queues = { "${rabbitmq.main.messages.queue}" })
public void recievedMessage(#Payload Mensagem item, Channel channel, #Header(AmqpHeaders.DELIVERY_TAG) long tag) throws InvalidMessageException {
if (item.getIdCliente().equals("69")) {
logger.info("Something went wrong to: " + item);
throw new InvalidMessageException();
} else {
logger.info("==> Message consumed successfully: " + item);
}
}
This is the configuration I have on my application.properties:
spring.rabbitmq.listener.simple.retry.enabled=true
spring.rabbitmq.listener.simple.retry.initial-interval=3s
spring.rabbitmq.listener.simple.retry.max-attempts=2
spring.rabbitmq.listener.simple.retry.multiplier=2
spring.rabbitmq.listener.simple.retry.max-interval=10s
When I throw an exception on purpose just to see the message moving to DLQ nothing happens. What's wrong here? What am I forgetting here?
Try adding
spring.rabbitmq.listener.simple.default-requeue-rejected=false
to your application.properties. I think the problem is that the failed deliveries are being requeued instead of being sent to the DLQ.
My spring/java consumer is not able to access the message produced by producer. However, when I run the consumer from console/terminal it is able to receive the message produced by spring/java producer.
Consumer Configuration :
#Component
#ConfigurationProperties(prefix="kafka.consumer")
public class KafkaConsumerProperties {
private String bootstrap;
private String group;
private String topic;
public String getBootstrap() {
return bootstrap;
}
public void setBootstrap(String bootstrap) {
this.bootstrap = bootstrap;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
}
Listener Configuration :
#Configuration
#EnableKafka
public class KafkaListenerConfig {
#Autowired
private KafkaConsumerProperties kafkaConsumerProperties;
#Bean
public Map<String, Object> getConsumerProperties() {
Map<String, Object> properties = new HashMap<>();
properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaConsumerProperties.getBootstrap());
properties.put(ConsumerConfig.GROUP_ID_CONFIG, kafkaConsumerProperties.getGroup());
properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
properties.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "100");
properties.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "15000");
return properties;
}
#Bean
public Deserializer stringKeyDeserializer() {
return new StringDeserializer();
}
#Bean
public Deserializer transactionJsonValueDeserializer() {
return new JsonDeserializer(Transaction.class);
}
#Bean
public ConsumerFactory<String, Transaction> consumerFactory() {
return new DefaultKafkaConsumerFactory<>(getConsumerProperties(), stringKeyDeserializer(), transactionJsonValueDeserializer());
}
#Bean
public ConcurrentKafkaListenerContainerFactory<String, Transaction> kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, Transaction> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConcurrency(1);
factory.setConsumerFactory(consumerFactory());
return factory;
}
}
Kafka Listener :
#Service
public class TransactionConsumer {
private static final Logger LOGGER = LoggerFactory.getLogger(Transaction.class);
#KafkaListener(topics={"transactions"}, containerFactory = "kafkaListenerContainerFactory")
public void onReceive(Transaction transaction) {
LOGGER.info("transaction = {}",transaction);
}
}
Consumer Application :
#SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
TEST CASE 1 : PASS
I started my spring/java producer and run the consumer from console. When I produce message form producer my console consumer is able to access the message.
TEST CASE 2 : FAILED
I started my spring/java consumer and run the producer from console. When I produce message form console producer my spring/java consumer is not able to access the message.
TEST CASE 3 : FAILED
I started my spring/java consumer and run the spring/java producer. When I produce message form spring/java producer my spring/java consumer is not able to access the message.
Question
Is there anything wrong in my consumer code ?
Am I missing any configuration for my kafka-listener?
Do I need to explicitly run the listener? (I don't think so since I can see on the terminal log connecting to topic, still I am not sure)
Okay you are missing AUTO_OFFSET_RESET_CONFIG in Consumer Configs
properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
auto.offset.reset
What to do when there is no initial offset in Kafka or if the current offset does not exist any more on the server (e.g. because that data has been deleted):
earliest: automatically reset the offset to the earliest offset
latest: automatically reset the offset to the latest offset
none: throw exception to the consumer if no previous offset is found for the consumer's group
anything else: throw exception to the consumer
Note : auto.offset.reset to earliest will work only if kafka does not have offset for that consumer group (So in you case need to add this property with new consumer group and restart the application)
I have a consumer consumes a message do some transformation and create a new Pojo and pass to a producer.
The producer sends the message in queue using the JmsTemplate.
The producer should set the headers of the original message like (JMSType, JMSCorrelationID, JMSExpiration, JMSDeliveryMode) to the new message to send.
But the producer should to change the replyTo Destination of the original message.
I haven't found a way to create a Destination and set to the JMSReplyTo.
Some have an idea how I can do that?
Maybe the JmsTemplate is not the correct class to do that.
public class Producer {
private final JmsTemplate jmsTemplate;
#Value("${jms-destination}")
private String destination;
public Producer(#Autowired JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public void send(final MessageHeaders headers, final Pojo pojo) {
Validate.notNull(order);
jmsTemplate.convertAndSend(destination, pojo, (message) -> {
final Destination replyToDestination = ???;
message.setJMSReplyTo(replyToDestination);
message.setJMSType((String) headers.get(JmsHeaders.TYPE));
message.setJMSCorrelationID((String) headers.get(JmsHeaders.CORRELATION_ID));
message.setJMSExpiration((long) headers.get(JmsHeaders.EXPIRATION));
message.setJMSDeliveryMode((int) headers.get(JmsHeaders.DELIVERY_MODE));
return message;
});
}
}
I have found only this way to do, but I don't like and I don't sure that this introduce side effect:
public class Producer {
private final JmsTemplate jmsTemplate;
#Value("${jms-destination}")
private String destination;
#Value("${jms-replyTo}")
private String replyTo;
public Producer(#Autowired JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public void send(final MessageHeaders headers, Pojo pojo) {
Validate.notNull(order);
jmsTemplate.convertAndSend(destination, order, (message) -> {
final Destination replyToDestination = buildReplyTo();
message.setJMSReplyTo(replyToDestination);
message.setJMSType((String) headers.get(JmsHeaders.TYPE));
message.setJMSCorrelationID((String) headers.get(JmsHeaders.CORRELATION_ID));
message.setJMSExpiration((long) headers.get(JmsHeaders.EXPIRATION));
message.setJMSDeliveryMode((int) headers.get(JmsHeaders.DELIVERY_MODE));
return message;
});
}
private Destination buildReplyTo() throws JMSException {
final Session session = jmsTemplate.getConnectionFactory().createConnection()
.createSession(false, Session.AUTO_ACKNOWLEDGE);
final Destination queue =
jmsTemplate.getDestinationResolver().resolveDestinationName(session, replyTo, false);
return queue;
}
}
Your solution creates side-along connections, which are not closed.
You should use existing session object and send your pojo manually through send API. Use getRequiredMessageConverter to convert your pojo.
public void send(final MessageHeaders headers, Pojo pojo) {
Validate.notNull(order);
final String responseQueue = "responseQ";
jmsTemplate.send(destination,
session -> {
Message message = getRequiredMessageConverter().toMessage(message, session);
message.setJMSReplyTo(session.createQueue(responseQueue)); //fill queue
//any other setters
return message;
});
}
// based on Spring JmsTemplate library
private MessageConverter getRequiredMessageConverter() throws IllegalStateException {
MessageConverter converter = jmsTemplate.getMessageConverter();
if (converter == null) {
throw new IllegalStateException("No 'messageConverter' specified. Check configuration of JmsTemplate.");
} else {
return converter;
}
}