Some messages are not received by Spring JmsListener - jms

I am using ActiveMQ as provider and JMS 2.0 API with Spring Boot. I have the same configuration in both sides producer and consumer like codes below:
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
props.setProperty(Context.PROVIDER_URL, "tcp://localhost:61616");
InitialContext ctx = new InitialContext(props);
ConnectionFactory connectionFactory = null;
connectionFactory = (ConnectionFactory) ctx.lookup("ConnectionFactory");
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
connection.start();
I want send a message from producer to consumer. This is how I try to send message:
// configs above
MessageProducer producer = session.createProducer(queue);
TemporaryQueue replyQueue = session.createTemporaryQueue();
TextMessage message = session.createTextMessage("hello World");
message.setJMSReplyTo(replyQueue);
producer.send(queue, message);
ctx.close();
On the consumer side I have:
#JmsListener(destination = "My-queue")
public void receiveMessage() throws JMSException, NamingException {
// same configs
MessageConsumer consumer = session.createConsumer(queue);
connection.start();
TextMessage receivedMessage = (TextMessage) consumer.receive();
System.out.println(receivedMessage.getText());
}
When I'm looking at console I see some of the messages did not received (maybe half of them and sometimes actually none) and they stayed in queue (in ActiveMQ terminal the queue did not get empty) until I stop and restart my application so the queue goes empty and the messages print in console. Can anybody help please?

Related

Spring AMQP - Return Exception Message From RabbitListenerErrorHandler

I'm trying to handle exception with an implementation of RabbitListenerErrorHandler in my project which uses Spring AMQP.
Here is how I defined my consumer:
#RabbitListener(queues = "inqueue", autoStartup = "true", concurrency = "3", returnExceptions = "true", errorHandler = "customRabbitListenerErrorHandler")
Here is my customRabbitListenerErrorHandler:
#Override
public Object handleError(org.springframework.amqp.core.Message message, Message<?> message1, ListenerExecutionFailedException e) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
return MessageBuilder.withBody(objectMapper.writeValueAsString(myCustomData).getBytes()).andProperties(e.getFailedMessage().getMessageProperties()).build();
}
My problem is that I can't deliver this exception message to consumer side. I'm getting this exception:
Caused by: org.springframework.amqp.AmqpException: Cannot determine ReplyTo message property value: Request message does not contain reply-to property, and no default response Exchange was set.
From this message I understood that there is no replyTo property in my messageProperties but I don't know how can get/found it. How can I send this exception message to consumer side?
The error handler should not return a org.springframework.amqp.core.Message message, it should just return myCustomData.
However, that should not prevent finding the replyTo header; please provide an MCRE so I can see what's wrong.

Rest Template release Connection from Pool

I have rest template config similar to the following. I am trying to release a connection from the pool if I get a status code that does not equal 2XX (long story but need this code). Is here a way I can get the connection Manager and release a specific connection?
#Bean
public RestTemplate restTemplate() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(20);
RequestConfig requestConfig = RequestConfig
.custom()
.setConnectionRequestTimeout(5000) // timeout to get connection from pool
.setSocketTimeout(5000) // standard connection timeout
.setConnectTimeout(5000) // standard connection timeout
.build();
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig).build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(requestFactory);
}
Looking for a way to accomplish something similar to the following
if(!httpStatusCode.substr(1).equals("2")) {
restTemplate.getConnectionPool().relase().thisConnection();
}
enter code here

Solace Session Recovery , message redelivery

I am using Spring DefaultMessageListenerContainer and JMS Message Listener to consume messages from Solace Queue. Client Acknowledgement is set to true.
In case of exception messages remain in the queue since they were not acknowledged and these are not redelivered. New messages that were pumped post exception are processed.
Have read about using session.recover but how do we get handle to session . Also tried setting maxredelivery to 3 . But not working.
public void onMessage(Message message) {
String text = null;
ALNTLogger.trace(CLAZZ_NAME, "onMessage()", "Message Received:");
try {
TextMessage textMessage = (TextMessage) message;
text = textMessage.getText();
ALNTLogger.trace(CLAZZ_NAME, "onMessage()", "Message Received: " + text);
Document xmlDocument = parseXml(text);
Map < String, String > values = getValues(xmlDocument);
saveValues(values);
message.acknowledge();
} catch (Exception ex) {
ALNTLogger.error(CLAZZ_NAME, "onMessage()", "Failed to process message:" + text);
throw new RuntimeException(ex);
}
}
Any help will be appreciated
It is expected that the message is not redelivered when using CLIENT_ACKNOWLEDGE acknowledgement mode with a DefaultMessageListenerContainer.
The Spring documentation states the following:
The listener container offers the following message acknowledgment
options:
"sessionAcknowledgeMode" set to "AUTO_ACKNOWLEDGE" (default):
Automatic message acknowledgment before listener execution; no
redelivery in case of exception thrown.
"sessionAcknowledgeMode" set
to "CLIENT_ACKNOWLEDGE": Automatic message acknowledgment after
successful listener execution; no redelivery in case of exception
thrown.
"sessionAcknowledgeMode" set to "DUPS_OK_ACKNOWLEDGE": Lazy
message acknowledgment during or after listener execution; potential
redelivery in case of exception thrown.
"sessionTransacted" set to
"true": Transactional acknowledgment after successful listener
execution; guaranteed redelivery in case of exception thrown.
You can use the last option, transactional acknowledgements, in order to have the message redelivered when the onMessage() method does not return normally.

Sending headers/body after the websocket session is established

I am using org.eclipse.jetty.websocket.client.WebSocketClient to establish a websocket connection.
After the initial handshake(Protocol switch/Upgrade) the websocket session is established.
Here is the code snipped i am using:
WebSocketClient client = new WebSocketClient();
client.start();
URI echoUri = new URI("destinationURI");
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setHeader("myCustomHeader", "CustomHeader");
client.connect(socket, echoUri, request);
Collection<WebSocketSession> sessions = client.getConnectionManager().getSessions();
for (WebSocketSession webSocketSession : sessions) {
webSocketSession.getRemote().sendString("<Custome message>");//I am able to recieve the messages //to the configured message handler
}
My message handler looks like:
#Override
protected void handleTextMessage(WebSocketSession session,
TextMessage message//This is what i sent above) throws Exception {
session.getHandshakeHeaders();//This has "myCustomHeader", "CustomHeader"
BinaryMessage binaryMessage = new BinaryMessage(new String(
"Hello . This is message sent from server").getBytes());
session.sendMessage(binaryMessage);
}
Is it possible to send a custom header, after the web socket session is established?
Here is what i tried:
WebSocketClient client = new WebSocketClient();
client.start();
URI echoUri = new URI("destinationURI");
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setHeader("myCustomHeader", "CustomHeader");
client.connect(socket, echoUri, request);
Collection<WebSocketSession> sessions = client.getConnectionManager().getSessions();
for (WebSocketSession webSocketSession : sessions) {
webSocketSession.getUpgradeRequest().setHeader("mySecondCustomHeader","MySecondCustomHeader");
webSocketSession.getRemote().sendString("<Custome message>");//I am able to recieve the messages //to the configured message handler
}
I am only getting myCustomHeader and not mySecondCustomHeader in session.getHandshakeHeaders()
#Override
protected void handleTextMessage(WebSocketSession session,
TextMessage message//This is what i sent above) throws Exception {
session.getHandshakeHeaders();//This has "myCustomHeader", "CustomHeader"
BinaryMessage binaryMessage = new BinaryMessage(new String(
"Hello . This is message sent from server").getBytes());
session.sendMessage(binaryMessage);
}
s it possible to send a custom header, after the web socket session is
established?
No, it is not possible. Once the HTTP negotiation has concluded, the connection only uses binary frames to communicate and cannot do more HTTP interactions.

JMS queue in Weblogic10 EJB2 session bean able to send but not to receive

I try to receive a JMS message in an EJB2 (legacy sucks ;-) stateless session bean, in weblogic 10.0.1, with bean managed transactions. Queue definition from jms folder looks like
<uniform-distributed-queue name="ReqQueue">
<default-targeting-enabled>true</default-targeting-enabled>
<delivery-params-overrides>
<delivery-mode>Non-Persistent</delivery-mode>
</delivery-params-overrides>
<quota>QuotaCrc</quota>
<jndi-name>xxx.ReqQueue</jndi-name>
<load-balancing-policy>Round-Robin</load-balancing-policy>
</uniform-distributed-queue>
<uniform-distributed-queue name="RespQueue">
<default-targeting-enabled>true</default-targeting-enabled>
<delivery-params-overrides>
<delivery-mode>Non-Persistent</delivery-mode>
</delivery-params-overrides>
<quota>QuotaCrc</quota>
<jndi-name>xxx.RespQueue</jndi-name>
<load-balancing-policy>Round-Robin</load-balancing-policy>
</uniform-distributed-queue>
The business method in the bean does not start a transaction, so the JMS operations are not transactional. The executed code is
InitialContext ictx = new InitialContext();
QueueConnectionFactory cf = (QueueConnectionFactory)
ictx.lookup("weblogic.jms.ConnectionFactory");
Queue responseQueue = (Queue) ictx.lookup("RespQueue");
conn = cf.createConnection();
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer receiver = session.createConsumer(responseQueue);
ObjectMessage response = (ObjectMessage) receiver.receive(30000);
The problem is that receiver.receive returns null immediately without any blocking, regardless of the contents of the queue. According to the JMS API doc., receiver.receive with a timeout returns null after the timeout or immediately if the destination is closed. The problem is the same if I use bean managed transactions, container managed transactions or no transactions at all. Posting a JMS message to another queue works. Receive returns null immediately regardless if I do a send before in the same method or not.
Why is the queue closed, or why does it seem so?
Unfortunately MDB is not an option because we have to tunnel a synchronous call through JMS (and I don't want to fool around too much in the Ball of Mud ;-)
Before
MessageConsumer receiver = session.createConsumer(responseQueue);
put
conn.start();
After you create the connection, it needs to be started to get into the receiver mode.
Try this
......
conn = cf.createConnection();
conn.start();
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
......

Resources