In the following this, there is code for a basic JMS synchronous receiver.
The question I have is this: When a message is delivered to the queue, because it is synchronous, it will automatically be available via the receiver.receive method. Is this correct?
If this is so, then after msg1 arrives on queue, while we are still processing receiver.receive(). what happens if msg2 arrives on queue.
since the call receiver.receive() has not returned, will it be able to still receive the message # 2?
msg2 will remain on the queue until another consumer calls receive().
Related
I'm using Camel for a while and I'm a huge admirer of its simplicity.
The use case
Given this simple route:
from("mock:some-route")
// split 1
.split().method("splitterBean", "split")
// now we have an ArrayList of n messages (let's say 10)
.to(ExchangePattern.InOut, "jms:some-thing");
If we assume that we have 10 messages after the split(), this route will immediately send 10 messages to the "to" endpoint. So jms:some-thing will receive all 10 messages at once.
The problem
--> Please note that the "out" endpoint is inOut, so we have timeouts in place when the receiver must acknowledge the message.
The application on the receiving end of jms:some-thing has to do quite some work for each message. As all 10 messages were written at the same time, the same timeout applies for all of them.
So we increased that timeout.
But one day, we will have 1000 messages and the timeout will again be to low.
What i want to archieve
I want to implement a pattern where I'll send only 1 message at once after the split, then sending the next after 1 message is acknowledged by the receiving system.
So instead of sending the 10 messages at once, I want
Send 1 message
Wait for the acknowledgment of that message
Send the next
Wait again
And so on..
How to implement such behavior?
I looked at the documentation, but none of the EIP components seem to fulfill that need?
Thanks for any input
You can have an intermediate seda queue with only one thread.
from("mock:some-route")
.split().method("splitterBean", "split")
.to("seda:your-seda-queue?waitForTaskToComplete=Always&timeout=0");
from("seda:your-seda-queue?waitForTaskToComplete=Always&timeout=0")
.to(ExchangePattern.InOut, "jms:some-thing");
By default, a seda queue will have a single consuming thread, and will block the calling thread until a consumer becomes available. More on seda details here
Saying that, your sending to a jms topic, which is really what you should be using to queue up your requests instead of a seda queue. You should look into implementing this logic asynchronously, and waiting on a reply topic rather than using a timeout.
I have setup a JMS queue that is fed by a single producer, and consumed by 8 different consumers.
I would like to configure my queue/broker so that one message being delivered to a consumer blocks the queue until the consumer is done processing the message. During the processing of this first message, the following messages may not be delivered to another consumer. It doesn't matter which consumer processes which message, and it is acceptable for the same consumer to consume many messages in a row as long as when it dies another consumer is able to pick up the rest of the unprocessed messages.
In order to do this, I have configured all of my consumers to use the CLIENT acknowledgement mode, and I have coded them so that message.acknowledge() is called only at the end of the message processing.
My understanding was that this should be sufficient to satisfy my requirements.
However I am apparently wrong, because it looks like my brojer (OpenMQ) is delivering the messages to consumers as fast as possible, without waiting for the consumer acknowledgement. As a result, I get multiple messages processed in parallel, one for each consumer.
I'm obviously doing something wrong, but I can't figure out what.
As a workaround, I figure I could create a durable subscription with a fixed client ID shared between all my consumers. It would probably work by only allowing one consumer to even connect to the broker, but I can't shake the feeling that this is a rather ugly workaround.
Does anyone have an idea of how I should configure my Broker and/or my Client to make this possible?
I want to implement the HTTP endpoint using Spring Integration, which listen to the http requests, sends the request data as messages to the channel and another endpoint should listen messages on this channel and process them.
Sounds simple. But what I want to achieve is:
Messages should be processed in order.
Messages should be processed asap (without delay after http request, if the queue is already empty).
The http request should be responded as soon as message is received, not after it is processed, so the sender will know only that message is received for processing.
I don't want to use external queues, like RabbitMQ.
So I need a QueueChannel for this. But if I understand correctly, the only way to receive messages from the queue is the poller. So the point 2 will not be satisfied. There will be small delay after message received and before poller sees it.
So the question is: is there any simple way to achieve this in Spring Integration which I don't see?
Of course I can implement it myself. For example creating SmartLifeCycle component, which listen on DirectChannel and just put the messages into java.util.concurrent.BlockingQueue, and also starts a dedicated thread which will wait on this queue and send the message into another DirectChannel for processing. So there will be no delay because thread will be unblocked as soon as BlockingQueue is not empty.
This all sounds like a "pattern" - some queue between two direct channels based on dedicated thread.
Maybe there is a simplier way, already implemented in Spring Integration, which I just don't see because of absense of expirience in this area?
Point 2 can be satisfied, even with a poller - just set the fixed-delay to 0 and/or increase the receive timeout (default 1 second); the poller thread will block in the queue until a message arrives; then immediately wait again.
You can also use an executor channel (the http thread hands off to the executor thread).
I have some theoretical question regarding "message loops"; particularly returning result of operations happening in a message loop that runs in a different thread. I have the situation where I'm having a TCP server listening for incoming messages. For each incoming message the server will authenticate the client who sent the message and two things may happen:
If the authenticated client has an attached handler the received message will be passed to the handler's message queue.
If the client has no handler a new one will be created and the same as above (the message will be passed to its message queue).
The handler is currently an object implementing the Callable interface so that it'll run in a different thread and its simple enough the get the result of the operation. Now for my problem: Each handler can have N amount of messages to be processed. The handler has a "message loop" like functionality that runs until a timeout occurs - a timeout in this case would be the socket's idle time reaching a predefined treshold. What I would like to know, how can I get Java to return a value from within the message loop without actually terminating the thread. Something like the following:
while (true) {
if (expired(socket))
break; // the callable will finish the call() method.
// get the first item from the queue.
message = messageQueue.poll();
result = process(message);
// I want to return the result to the caller which is in a different thread.
}
Now obviously a return statement would stop the message loop and if the messageQueue contains more messages they'll be lost. Another naive approach would be to use a callback-like mechanism, which requires an extra object + I still need to synchronize the caller with the Callable in the background thread. Something like wait & notify although I have K threads running in the background.
What would be the sophisticated way to handle this situation of returning results of operations from within a message-loop in a different thread, without terminating the thread itself?
#Edit:
I'll give a description of the whole process so that it clarifies what is happening here.
A client sends a message (xml string) to the application through tcp sockets.
The application authenticates the client, and if the client has no associated handler it'll create one.
The app will push the message to the queue of the handler.
The handler runs in a separate thread waiting for incoming messages from clients they're associated with, they MUST NOT handle messages for other clients.
When the handler picks up a message it'll transform it into a SOAP message and will forward it to another system through TCP socket.
When the handler recieves the response it needs to delegate it back to the caller without terminating its message-loop.
So the caller is something like a Dispatcher dispatching messages to the threads that are running the handlers associated with the sender of the message. It also collects the response from the handlers and sends them back to the correct clients.
Each handler, currently has their own message queue where only those messages are pushed which the particular handle has to process. When a handler starts up, it'll open a TCP socket to the target system where they'll forward the incoming messages after transformations were applied. When the handler reaches the maximal allowed idle time (The socket were opened without sending a request) the socket will be closed and the message-loop stopped. At this point the handler will finish its execution. the purpose of this, is to have a socket for each individual clients through which they can send multiple requests without the need for the target system to do another authentication.
Few options/questions come to mind:
Is there a problem to terminate the thread, check the returned result and then re-submit this task to the same thread pool? You will get a result, analyze it, and then resubmit to the pool and continue the work
As this thread runs, it can submit the statuses to a different ("external") queue which is analyzed outside this thread. An independent thread always run and check this queue
That's as far as I could think on how to...
It depends on...
If you want to return simple type you can use a thead safe result queue (global or by caller).
Propably thread pool will be more suitable in your case.
I belive that the most universal way is callback mechanism.
How do I acknowledge a message when I am using a message listener?
I get the following error when I try to do an acknowledge in my message listener.
A synchronous method call is not permitted when a session is being used asynchronously: 'acknowledge'
You're talking about JMS messages acknowledgement as in Message.acknowledge()?
That error seems a little odd. If you aren't using transactions or auto-acknowledge, I'd think you need to call that method. And if you're doing async listening, where are you doing to do it aside from the onMessage() method?
Is this call being done in the same thread that got the onMessage() call? In other words, in onMessage() or in some method called from onMessage()? If not, you're breaking the thread rules of JMS. Sessions and producers/consumers and anything further down (like Messages) aren't thread safe. You need to make sure you're not touching them from multiple threads. If you're in the middle of an onMessage() call and you somehow arrange another thread to do that Message.acknowledge() call, you deserve to fail because of the thread problem. If so, move that call back on the same thread that onMessage() is running in.
This is an example for Queue Session
session = connection.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
Only if
if (session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) //
Then can we have
message.acknowledge();
Check the Message class here (http://java.sun.com/j2ee/1.4/docs/api/javax/jms/Message.html)
To amplify the first answer a bit for posterity: The OP probably created his session with acknowledgement mode set to Session.AUTO_ACKNOWLEDGE, which means the provider automatically acknowledges the messages as they are delivered on the connection (for synchronous delivery) or after your MessageListener#onMessage() is called (for asynchronous delivery).
He got the exception because his explicit call to Message#acknowledge() is not valid in this mode. As Buhake Sindi points out, if you wish to manually acknowledge messages, you must choose Session.CLIENT_ACKNOWLEDGE when you set up the session from which the MessageConsumer will be created. Then, each time you call Message#acknowledge(), the current message, along with any other delivered but unacknowledged messages delivered to this session/consumer, will be acknowledged back to the broker.
An asynchronous message, by definition, is not expected to be acknowledged at the protocol level. If you want an acknowledgement you must build it into your application, at which point the questions is why aren't you using a synchronous scheme.
Check to see if your session requires acknowledgement by using getAcknowledgeMode() method off the session, if it does then just call the acknowledge() method on the message itself