Camel route runs multiple times for a single jms topic message - apache-camel

I'm having a problem with handling JMS topic message using Apache Camel.
Here's a route (Spring context fragment) I use to read and handle the message:
<camel:route id="refreshParameters" autoStartup="true" >
<camel:from uri="activemq:topic:{{refreshParameters.inputTopic}}" />
<camel:log message="handling refresh topic"></camel:log>
<camel:log message="${body}" />
<camel:unmarshal ref="RefreshParametersRequest" />
<camel:bean ref="RefreshParametersHandler" method="refreshParameters" />
</camel:route>
The route runs multiple times (about 60) for each message. From my undestanding it should be executed only once.
Here's a log piece:
thread #243 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #221 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #237 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #221 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
thread #237 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
thread #246 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #246 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
thread #243 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
thread #248 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #242 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #248 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
thread #242 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
thread #239 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #240 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #239 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
thread #226 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #249 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #240 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
thread #226 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
thread #249 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
thread #206 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #210 - JmsConsumer[refreshterm]:) handling refresh terminal topic
thread #210 - JmsConsumer[refreshterm]:) {"uId":"44298b83-9a88-4b80-9b16-e60d1cfeaf9a","tid":"12340003","iid":"TMS0","m":false}
Route executions seem to be run asynchronously and not being a result of handling reattempting.
Moreover, this route is the only topic's subscriber, but when handling stops the message is still in the topic. Shouldn't it be deleted as there are no more subscibers this message can be delivered to?

Related

Completed exchange in the scope of http4-component

I have a simple Camel route consuming messages from ActiveMQ, processing and forwarding them to Rest webservices:
from("activemq:MyQueue").process("MyProcessor").to("http4:uri");
I configure concurrentConsumers=100 in the connectionfactory from activemq-component.
In the documentation:
if asyncConsumer is disabled(default) then the Exchange is fully processed before the JmsConsumer will pickup the next message from the JMS queue
Question:
In my route, when is the exchange of each message is fully processed? After the http-callee receives http response? If that is the case, I assume, my route configuration means:
At beginning, 1 message is consumed from each consumers and forwarded to the http
Each of these 100 consumers is waiting and will only consume again if the current http call gets http response from the current message.
Another question:
I found out that the default value of http4 component option connectionsPerRoute=20. As I have 100 consumers, should I set connectionsPerRoute=100?
Thank you,
Hadi
each jms thread runs simultaneously without knowing each other. in your example 100 threads are processed at the same time without getting blocked.You do not need to play in the number of threads of the http component, as this is done through jms threads from start to finish.

Stopping Camel Route when no more message in ActiveMQ

Is there a way using which we can stop the Camel route if we don't have any more message in ActiveMQ? My required scenario.
Fetch all the message from ActiveMQ queue and process them.
Poll for 2-3 more times to check if we have any other new message, is yes execute step #1.
If no message in present stop the route and start it back after say 5 min (which I guess can be achieved by Polling Strategy).
Have a look at this answer. It polls the queue with a scheduler and a polling strategy (POJO).
With the scheduler you can choose the interval of polling
With the timeout of the polling strategy consumer you can stop consuming (e.g. if no message arrives for 5 seconds the queue is probably empty)
If you want to stop/start the consumer completely, you can add Camel Control Bus to the mix. You could then start and stop the consumer route.

Camel Transacted: MQ Session closed on every commit

I have:
Camel route (transacted=true), consuming from an MQ Queue
Using Spring's WebSphereUowTransactionManager
Transactionality works
Running on IBM Liberty
But, I get this message:
Setup of JMS message listener invoker failed for destination 'MY.QUEUE' - trying to recover.
Cause: Local JMS transaction failed to commit; nested exception is com.ibm.msg.client.jms.DetailedIllegalStateException:
MQJCA1020: The session is closed.
The application attempted to use a JMS session after it had closed the session.
Modify the application so that it closes the JMS session only after it has finished using the session.
This appears to be related to this other Stack Overflow question, but I've tried changing the configuration in server.xml, with no success.
You can try setting cacheLevelName=CACHE_CONSUMER which allows to re-use the JMS consumer and avoids endless of creation/destruction of JMS resources, as indicated by the error message may be the cause.
You can see more about the importanse of cache levels on the Camel JMS documentation: http://camel.apache.org/jms

CAMEL - Channel Closed exception not caught using onException

I am opening this question as I didn't find any answer to problem in the web.
I have used camel to implement a TCP/IP server and I have defined a route like this:
from("netty4:tcp://0.0.0.0:3510")
.to("file:target/outbox");
and I have a client which sends data to this server. When I disconnect this client I can see in my logs this exception:
[Camel (camel-client) thread #0 - NettyEventExecutorGroup] WARN o.a.c.component.netty4.NettyConsumer - Closing channel as an exception was thrown from Netty. Caused by: [java.io.IOException - an existing connection was forcibly closed by the remote host]
My problem is that I am not able to catch this exception using onException clause.
onException(IOException.class)
.log("Exception: ${body}")
.handled(true)
.process(new ExceptionProcessor());
The program does not stop but I want to catch it to handle when the client is disconnected.
Note that I can catch other exceptions which are thrown inside my route.
You cannot handle it as exception, because exception is already catched in netty and logged. This exception is not propagated from netty to netty component.
The solution is a bit tricky. You can extend SimpleChannelInboundHandler and override method channelInactive as described in How can I detect network disconnection in Apache Camel?.
In this custom handler you can set custom properties on exchange with additional information, which is relevant in your application.

Asynchronous delivery support using Apache Camel routes and ActiveMQ

Please help me in finalizing architecture for Asynchronous delivery support using Apache Camel and ActiveMQ and below I have explained point by point basis about my requirement.
I have Jetty Server receiving incoming messages and ActiveMQ to store it in disk using Kaha DB.
Active MQ sends ack once it stores in kaha DB back to client.
I have Spring AbstractPollingMessageListenerContainer JMS Message listener which picks up the message from activemq queue every 1 second and dispatch to Camel HTTP endpoints and then finally sent to actual remote receivers.
Once Dispatcher thread gets response from remote receivers it deletes message from ActiveMQ.
Assume that I have many slow remote receivers in that case my Dispatcher thread created by AbstractPollingMessageListenerContainer remains blocked until I get response from remote receivers. This results to creation of new Dispatcher threads since already created Dispatcher threads are not able to dispatch new messages from ActiveMQ queue.
Now creation of many Dispatcher threads result into more CPU usage which impacts overall performance.
Now my requirement is I want Dispatcher thread only to dispatch messages from ActiveMQ queue to HTTP endpoint and forget and also not do acknowledgement so that message is still in queue.
Also I will not let Dispatcher thread to wait till I get response so I have thought to handle response using separate thread and this same thread will only delete message from ActiveMQ queue.
So my current architecture is like below:
Camel Jetty Server ----> ActiveMQ queue ----> Dispatcher Thread ---> Camel Direct endpoint ----> Camel HTTP endpoint ---> remote receivers sending response back ---> response ---> Dispatcher Thread (sends ack to delete messages from ActiveMQ queue) ----> ActiveMQ Queue.
Here I feel since we are using Direct endpoint which is synchronous so Dispatcher thread remains active till it gets response and so same dispatcher thread is not able to process further new message from ActiveMQ queue.
Please suggest if some thing else I can use here to avoid Direct endpoint.
I used SEDA endpoint but drawback is it processes 1 message using 1 thread and also gets blocked till it gets response from receivers.
In this approach previously Dispatcher thread gets blocked but now Seda consumer threads gets blocked and could not dispatch new messages from in memory queue of SEDA towards remote receivers.
I feel some kind of design which helps me in keep on sending message to remote receivers and only when response comes back some daemeon thread gets notified and it will handle acknowledgement towards activeMQ. Also I thought to use NIO framework implementation like Camel netty/netty4-http component but could not find exact usage and how to fit it in current architecture.
Modified architecture should be like below:
Camel Jetty Server ----> ActiveMQ queue ----> Dispatcher Thread--->Unknown Stuff ----> Camel HTTP Endpoint ---> remote receivers sending response back--->Unknown Stuff (sends ack to delete messages from ActiveMQ queue) ----> ActiveMQ Queue
Please help me in finalising Unknown Stuff and I am posting my query after doing enough R & D.
Also new ideas are welcome and please give me idea with a restriction that I must persist the message and delete it only after getting success response from remote receiver. Also I have to design architecture only using Apache Camel routes.
Route Definitions:
1. Dispatcher Route:
from(fromUri)to(toUris);
fromUri:
[ActiveMQueue.http1270018081testEndpoint1:queue:ActiveMQueue?maxConcurrentConsumers=15&concurrentConsumers=3&maxMessagesPerTask=10&messageListenerContainerFactoryRef=AbstractPollingMessageListenerContainer ]
ToUris:
[ActiveMQ.DLQ:queue:ActiveMQ.DLQ, direct:http1270018081testEndpoint1]
2.Remote Receiver Proxy Route:
fromUri:direct:http1270018081testEndpoint1
from(fromUri).to(toUri).process(responseProcessor)
toUri:http://127.0.0.1:8081/testEndpoint1?bridgeEndpoint=true
responseProcessor: To process response received by remote receiver.
Overall Route looks like below:
Dispatcher Route---> Remote Receiver Route---> Remote Server
JMS message acknowledgement is done under the covers, so your only way to really "send the acknowledgement back to the queue" is to use a JMS transaction (doesn't need to be XA)
It sounds like a LLR-style transaction would be useful and drastically simplify things for you. If you consume the message from the queue using a JMS-local transaction, and only have one other endpoint, the message will only be acknowledged and removed from the queue when the http send is completed-- even though HTTP doesn't support transactions. You can then have a number of concurrent consumers to run in parallel and combine with throttling to help with rate limiting.
from: amq:queue:INPUT.REQUESTS?.. concurrentConsumers.. and transacted enabled
throttle
to: http://url

Resources