JMS temporary queue discards first message - java

I'm sending JMS requests to a Weblogic 10.3 server through a named JMS queue, and receive a reply back through a temporary queue.
Client (barebone):
//init
Destination replyQueue = session.createTemporaryQueue();
replyConsumer = session.createConsumer(replyQueue);
...
//loop
TextMessage requestMessage = session.createTextMessage();
requestMessage.setText("Some request")
requestMessage.setJMSReplyTo(replyQueue);
requestProducer.send(requestMessage);
Message msg = replyConsumer.receive(5000);
if (msg instanceof TextMessage) {
...
} else { ... }
//loop end
Server MDB (message driven bean):
public void onMessage(Message msg) {
if (msg instanceof TextMessage) {
...
TextMessage replyMessage = jmsSession.createTextMessage();
replyMessage.setText("Some response");
replyMessage.setJMSCorrelationID(msg.getJMSCorrelationID());
replyProducer.send(replyMessage);
}
}
The problem is that the very first server reply is often lost! That is, the replyConsumer.receive(5000) ends with timeout for every 4th-5th replyConsumer. When the consumer receives the first answer, then it continues to receive all the rest, so the problem is only with the first message send through the temporary queue after the temp queue has been created.
My question: Do I have to set something special for the temporary queue in order it works from the very start after being created? Or any other hint?
Further info:
When testing against my local development machine, the temp queues work without problem. The messages are getting lost only when testing against our clustered Weblogic server. However, I have switched off all cluster members but one instance.
I have verified that the server successfully replies all the requests that the client sends (by counting the sent requests and sent replies). The server replies in the order of milliseconds, even for the lost replies.
When I replace the temporary queue with a regular named queue, the problem disappears! So the problem doesn't seem (to me) to be in my code.
I've also tried to modify expiration, persistency, delay etc. of the reply message, but without success. This way I excluded the scenario that the response arrives earlier than the client begins to read the queue, and then the message immediately expires not giving the client a chance to process it.
Edit: Instead of the synchronous replyConsumer.receive(5000) I've also tried to use the asynchronous replyConsumer.setMessageListener(this). The behaviour hasn't changed, first messages are still getting lost for temp queues.
Edit: It seems that there's something wrong with the Weblogic server (or cluster) I am using. Because when I deployed the server application to another Weblogic cluster we have, everything began to work correctly! Both clusters should be configured identically - so where's a difference? It scares me that the Weblogic signals no error.

Your problem seems to be that sometimes the server is receiving the publish and discarding it before your consumer has started receiving.
The way around it is to use the asynchronous receive (replyConsumer.setMessageListener) calls instead of the blocking call you currently have (replyConsumer.receive(5000)) and to add the call to the code with the rest of your consumer code.
That way, you are already listening for replies before you send out the request.
Hope that helps.
Edit: Just read that you are using a temporary queue, so my first sentence is not correct. However as an experiment try the rest of my response to see if it changes the behaviour you are seeing

Related

Can two consumers get same set of messages while retrieving messages using an Pull based Manner?

So I have a one client-server based ecosystem where I am using RabbitMQ as a persistent Middleware.
Now the flow of a single message goes like this.
Step-1: Client A sends a message to the server with the destination
being set to Client B in the metadata of that message.
Step-2: Server upon receiving a message pushes the message to the
RabbitMQ and sends Client B a notification that he has some messages
to fetch.
Step-3: Client B upon getting notified calls the fetch message API to
get messages from the server.
Step-4: On the server, after getting called from the Client B pulls
messages from the RabbitMQ using the pull-based approach
(channel.basicGet(queueName, false)) and hands over the list of
messages.
Now in the above flow, there are few things that I have some doubt with.
First of all, if my client receives two notifications and calls the pull message API twice, there might be a concurrency problem.
Suppose I am not sending the message Acknowledgement while getting the message but I am sending afterwards, then can It be possible that the same message being sent to two pull API? If so is there any way to prevent this from happening?
Sample Code to Get Message From the MQ:
long currentMessageCount = channel.messageCount(QUEUE_NAME);
while (currentMessageCount-- > 0) {
GetResponse getResponse = channel.basicGet(QUEUE_NAME, false);
if (getResponse == null) {
break;
}
AMQP.BasicProperties props = getResponse.getProps();
Envelope envelope = getResponse.getEnvelope();
int messageCount = getResponse.getMessageCount();
byte[] body = getResponse.getBody();
/*
Do some logic
*/
channel.basicAck(envelope.getDeliveryTag(), false);
}
TIA
basicGet is rarely the correct solution. In Step 2, the client should be consuming from RabbitMQ. No notification that a message is ready is necessary. RabbitMQ will send the message to Client B as soon as it's in the queue. Step-3 and Step-4 become unnecessary.
NOTE: the RabbitMQ team monitors the rabbitmq-users mailing list and only sometimes answers questions on StackOverflow.

apache camel - add message alert to deadletter queue

String queueA = "rabbitmq://host:5672/queue-a.exchange?queue=queue-a.exchange..etc
from(queueA)
.routeId("idForQueueA")
.onException(Exception.class)
.maximumRedeliveries(0)
// .processRef("sendEmailAlert") * not sure this belongs here*
.to(deadLetterQueueA)
.useOriginalMessage()
.end()
.processRef("dataProcessing")
.processRef("dataExporting")
.end();
Explaining the code above:
Messages are taken from queueA. Upon various processes being successful the message is consumed. If it fails its added to the dead letter queue "deadLetterQueueA". This all works ok.
My question is
When messages arrive in the deadletter queue I want to add alerts so we know to do something about it... How could I to add an email alert when a message arrives in the dead letter queue. I dont want to lose the original message if the alert fails - nor do I want the alert to consume the message.
My thoughts are.. I would need to split the message on an exception so its sent to two different queues? One for the alert which then sends out an email alert and then consumes itself. Then one for the dead letter queue that just sites there? However I'm not sure how to do this?
You can split a message to go to multiple endpoints using a multicast (details here):
.useOriginalMessage().multicast().to(deadLetterQueueA, "smtp://username#host:port?options")
This uses the camel mail component endpoints described here. Alternatively, you can continue processing the message after the to. So something like:
.useOriginalMessage()
.to(deadLetterQueueA)
.transform().simple("Hi <name>, there has been an error on the object ${body.toString}")
.to("smtp://username#host:port?options")
If you had multiple recipients, you could use a recipients list
public class EmailListBean {
#RecipientList
public String[] emails() {
return new String[] {"smtp://joe#host:port?options",
"smtp://fred#host:port?options"};
}
}
.useOriginalMessage()
.to(deadLetterQueueA)
.transform().simple("...")
.bean(EmailListBean.class)
Be careful of using JMS queues to store messages while waiting for a human to action them. I don't know what sort of message traffic you're getting. I'm assuming if you want to send an email for every failure, it's not a lot. But I would normally be wary of this sort of thing, and chose to use logging or database persistence to store the results of errors, and only use a JMS error queue to notify other processes or consumers of the error or to schedule a re-try.
There are two ways you can do this , but based on your message volume you might not want to send email on every failed message.
You can use the solution provided by AndyN , or you can use the Advisory Topics ActiveMQ.Advisory.MessageDLQd.Queue.* , whenever a message gets in to the DLQ the enqueue count of the topic will increase by 1 . By monitoring the Queue Depth you might now be able to send a mail to based on the number of the errors that ocurred.
If you want to do it at the producer end. You can use any one of the solutions provided by AndyN

Whats the best way to use JMS for this requirement

I need a setup where messages can be transmitted to a queue or topic which is listened to by 2 or more servers.
The consumer is a specific client who will access one of those 2 servers and it is not known ahead of time which server the client will check from. The message will have an ID on it which correlates to the correct client.
There may be multiple messages at any time waiting to be consumed by various clients accessing these servers.
How can I accomplish this? Queue, topic? point-to-point or publish subscribe? What exact setup would do this trick?
Here's another way to look at the scenario: imagine multiple towns which have a community mail box. The residents of these towns do not have specific addresses rather they are constantly moving around between the towns. Someone needs to send a message to another person, so they create the mail and it gets copied and routed to each town's mailbox waiting to be received. When the right person checks and finds the message addressed to him, the message is consumed and destroyed on all the other mailboxes ensuring the same message is not read again.
So the JMS queue or topic is this mailbox, and the clients connecting to these servers (which specifically are web servers in a clustered environment) are the people. Multiple messages addressed to different people can exist at the same time.
Whats the best way to do this using JMS?
If you need to address messages to specific clients, you can use consumer-side selectors, here's a round trip example:
Server Sends
QueueSender queueSender = queueSession.createSender(queue);
queueSender.setDeliveryMode(DeliveryMode.PERSISTENT);
TextMessage message = queueSession.createTextMessage("Hello John!");
message.setObjectProperty("ToAddress", "John-123");
queueSender.send(message);
Consumer Receives
QueueConnection queueConn = connFactory.createQueueConnection();
QueueSession queueSession = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueReceiver queueReceiver =
queueSession.createReceiver(queue, "ToAddress = 'John-123'");
queueConn.start();
TextMessage message = (TextMessage) queueReceiver.receive();
The client creates a queueReceiver using the selector ToAddress=John-123, so only messages that match that selector are delivered to that client; other messages go to different consumers based on their selector.
If queuereceiver 'John-123' is not connected, any messages addressed to him simply accumulate in the queue. If you want to receive messages in real time, the receiver needs to be connected, always. To check for messages intermittently (sort of like checking email a few times a day), there's not too much overhead associated with creating a receiver, checking for messages, then disconnecting, however, avoid doing that repeatedly (1000's of times, or more); if that's the case, just keep the receiver connected all the time.
Hope that helps,

JMS Listener & Sender - Spring Framework

I want to understand a java program and need to modify which was developed using jms spring framework. Typically it has JMS receiver & sender, it receives a message from request queue and will invoke a job (another java program) once the job is completed the sender will send response to response queue. Have couple of questions which are below,
The request message is not deleted until response posted into response queue successfully. How its been achieved what is the logic behind it.
I want to write a functionality of writing response into flat file when sender fails to send message (by catching JMS exception). Once the sender queue is up and running i will read flat file and will send responses. The reason i need is because its involved in job processing could be in hours if job failed then input message will be read again by receiver. I want to avoid duplicate processing. Please suggest your ideas here.
Without seeing the configuration it's hard to answer these questions, but best guess is that #1 is because the app is using a transactional session. This means all updates on that session are not completed until the transaction is committed.
Just catch the exception and write the data; as long as the transaction commits (because you caught the exception) the input message will be removed.

Architecture advice about managing UDP calls

I would like to have an advice for this issue:
I am using Jbos 5.1.0, EJB3.0
I have system, which sending requests via UDP'S to remote modems, and suppose to wait for an answer from the target modem.
the remote modems support only UDP calls, therefor I o design asynchronous mechanism. (also coz I want to request X modems parallel)
this is what I try to do:
all calls are retrieved from Data Base, then each call will be added as a message to JMS QUE.
let's say i will set X MDB'S on that que, so I can work asynchronous. now each MDB will send UDP request to the IP-address(remote modem) which will be parsed from the que message.
so basicly each MDB, which takes a message is sending a udp request to the remote modem and [b]waiting [/b]for an answer from that modem.
[u]now here is the BUG:[/u]
could happen a scenario where MDB will get an answer, but not from the right modem( which it requested in first place).
that bad scenario cause two wrong things:
a. the sender which sent the message will wait forever since the message never returned to him(it got accepted by another MDB).
b. the MDB which received the message is not the right one, and probablly if it was on a "listener" mode, then it supposed to wait for an answer from diffrent sender.(else it wouldnt get any messages)
so ofcourse I can handle everything with a RETRY mechanisem. so both mdb's(the one who got message from the wrong sender, and the one who never got the answer) will try again, to do thire operation with a hope that next time it will success.
This is the mechanism, mybe you could tell me if there is any design pattren, or any other effective solution for this problem?
Thanks,
ray.
It's tough to define an exacting solution without knowing the details, but I will assume that when a response is received from a modem (either the correct one or not), it is possible to determine which exact modem the request came from.
If this is the case, I would separate out the request handler from the response handler:
RequestMDB receives a message from the [existing] queue, dispatches the request and returns.
A new component (call it the ResponseHandler) handles all incoming responses from the modems. The response sender is identified (a modem ID ?) and packages the response into a JMS message which is sent to a JMS Response Queue.
A new MDB (ResponseMDB) listens on the JMS Response Queue and processes the response for which the modem ID is now known.
In short, by separating concerns, you remove the need for the response processing MDB to only be able to process responses from a specific modem and can now process any response that is queued by the ResponseHandler.
The ResponseHandler (listening for responses from the modems) would need to be a multithreaded service. You could implement this as a JBoss ServiceMBean with some sort of ThreadPool support. It will need a reference to the JMS QueueConnectionFactory and the JMS response queue.
In order to handle request timeouts, I propose you create a scheduled task, one for each modem, named after the modem ID. When a request is sent, the task is scheduled for execution after a delay of the timeout period. When a response is received by the ResponseHandler, the ResponseHandler queues the response and then cancels the named task. If the timeout period elapsed without a cancellation, the scheduled task executes and queues another request (an reschedules the timeout task).
Easier said than done, I suppose, but I hope this helps.
//Nicholas

Categories

Resources