Exchange id in camel request ends with even number - apache-camel

I am using Apache Camel in OSGI scenario using Karaf in version 2.15.1. I am using the exchange.getExchangeId() to print the exchange id in a request/reply. The exchange pattern is set to InOnly. The route looks like this:
<route id="ip_client_rpc">
<from uri="restlet:http://localhost:7070/lsp/patron/id?restletMethod=POST&synchronous=true"/>
<to uri="log:${headers}"/>
<setExchangePattern pattern="InOnly"/>
<process ref="rabbit_client"/>
<to uri="log:${headers}"/>
</route>
However when I print the exchange id sent to the rabbitmq queue it always ends with an even number.
Request from client:ID-VirtualDev-49301-1443430754519-5-6
Request from client:ID-VirtualDev-49301-1443430754519-5-8
Request from client:ID-VirtualDev-49301-1443430754519-5-10
Request from client:ID-VirtualDev-49301-1443430754519-5-12
Request from client:ID-VirtualDev-49301-1443430754519-5-14
Is there a reason why the final digit is always even? Is there another exchange being created that I am missing?
Thanks

Camel uses the same id generator for generating unique ids for different things, its just by chance that its even in this case. Could be that a breadcrumb or message id was also generated that takes the odd number.

Related

Apache Camel AMQP with selector is consuming any message

I am trying to use selectors on an amqp with Azure Service Bus consumer. However, for some reason the route is also consuming messages that do not match the selector.
Here's an example:
This route generates messages and append a header:
<route id="MessageGenerator">
<from uri="timer:generator?delay=5000&period=5000"/>
<setHeader headerName="INSTANCE_ID">
<simple>{{env:INSTANCE_ID}}</simple>
</setHeader>
<to uri="amqp:queue:external_queue" />
</route>
While this route should consume only those that contain INSTANCE_ID matching 2 possible values: env:INSTANCE_ID or Any.
<route id="ExternalConsumer">
<from uri="amqp:queue:external_queue?selector=INSTANCE_ID IN ('{{env:INSTANCE_ID}}', 'Any')"/>
<log message="{{env:INSTANCE_ID}} consumed message with Instance ID: ${header.INSTANCE_ID}" logName="AMQP_TEST" loggingLevel="INFO"/>
</route>
But the the log shows that it is consuming any message, regardless of the selector specifying which ones.
Am I missing something?
Thanks!
Issue here was that Azure Service Bus does NOT support selectors on queues. I switched to topics, which already have filters per subscription.

Camel-http httpclient timeout from exchange headers

I have a http component in my route in which I want to pass timeout value from exchange header's.
http://foo.com?httpClient.soTimeout=5000
How can we do this in Spring DSL.
Is is possible to do something like:
<to uri="http://foo.com?httpClient.soTimeout=${in.headers.timeout}"/>
Unfortunately, no, <to> DSL will create the endpoint and the producer before any exchange is received and for HTTP component SO_TIMEOUT is not a parameter that you can change in runtime (here's a list of what you can change).
That being said, if you are using Camel 2.16+ you can easily do it with Dynamic To endpoint. In your case that would be:
<toD uri="http://foo.com?httpClient.soTimeout=${in.headers.timeout}"/>
Otherwise, you'll have to use the Dynamic Recipient List EIP:
<setHeader headerName="theHeader">
<simple>http://foo.com?httpClient.soTimeout=${in.headers.timeout}</simple>
</setHeader>
<recipientList>
<header>theHeader</header>
</recipientList>

Apache Camel Exchange to Propagate from one process to another

I am looking out for a way by which in Apache Camel, I can stop a exchange to propagate from one process to another, without stoping and restarting the route itself. I had below route configured and what I am basically looking out is to return the exchange from messageMultiplierProcessor based on some conditions without changing/modifying the exchange body or setting/resetting it headers.
<route id="business-logic-route">
<from uri="direct:business-logic-endpoint"/>
<setProperty propertyName="esq.route.name">
<constant>TestRoute</constant>
</setProperty>
<process ref="messageMultiplierProcessor" />
<process ref="calculatedFieldsProcessor" />
You can conditionally stop a route at any point using "when" & "stop":
<when>some condition</when>
<stop/>

Camel: communicating between two routes

I'm basically new to camel. I set up a camel context with two routes that are using seda endpoints.
Simplyfying, all starts with a "from" file endpoint (sorry for the terminology if wrong) listening on a directory:
<route>
<from uri="file:mydir"/>
<process ref="a bean that change the body of the message by setting a custom object"/>
<to uri="seda:incoming"/>
</route>
<route>
<from uri="seda:incoming"/>
<process ref="a bean that does something with the custom object above"/>
....
</route>
now, what described above works perfectly but i need to change seda with activemq queues and after doing that the body of the message received by the 2nd processor is empty.
How can I obtain the same behaviour of seda endpoints using activemq channels?
exchange.getIn().setBody(myCustomBean)
and
exchange.getIn().setHeader("inputfile", aFileInstance)
If you expect to get some result when aquiring from activemq queue, you should send serializable object to queue. Otherwise object will not be transferred.
At your case there's no guarantee that myCustomBean and aFileInstance are serializable.
Basically try sending the Strings into the queue. Or make your objects serializable.

Throttling based on content

I would like to know if it's possible with Camel to do throttling based on the content of the exchange.
The situation is the following: I have to call a webservice via soap. Among, the parameters sent to that webservice there is a customerId. The problem is that the webservice send back an error if there are more than 1 request per minute for a given customerId.
I'm wondering if it would be possible to implement throttling per customerId with Camel. So the throttling should not be implemented for all messages but only for messages with the same customerId.
Let me know how I could implement this or if I need to clarify my question.
ActiveMQ Message Groups is designed to handle this case. So, if you can introduce a JMS queue hop in your route, then just set the JMSXGroupId header to the customerId. Then in another route, you can consume from this queue and send to your web service to get the behavior you described.
also see http://camel.apache.org/parallel-processing-and-ordering.html for more information...
While ActiveMQ Message Groups would definitely address the parallel processing of unique customer ID's, in my assessment Claus is correct that introducing a throttle for each unique group represents an unimplemented feature for Camel/ActiveMQ.
Message Groups alone will not meet the SLA described. While each group of messages (correlated by the customer ID) will be processed in order with one thread per group, as long as requests take less than a minute to receive a response, the requirement of one request per minute per customer would not be enforced.
That said, I would be very interested to know if it would be possible to combine Message Groups and a throttle strategy in a way that would simulate the feature request in JIRA. My attempts so far have failed. I was thinking something along these lines:
<route>
<from uri="activemq:pending?maxConcurrentConsumers=10"/>
<throttle timePeriodMillis="60000">
<constant>1</constant>
<to uri="mock:endpoint"/>
</throttle>
</route>
However, the throttle seems to be applied to the entire set of requests moving to the endpoint, and not to each individual consumer. I have to admit, I was a bit surprised to find that behavior. My expectation was that the throttle would apply to each consumer individually, which would satisfy the SLA in the original question, provided that the messages include the customer ID in the JMSXGroupId header.
I came across a similar problem and finally came up with the solution described here.
My assumptions are:
Order of messages is not important (though it can be solved by re-sequencer)
Total volume of messages per customer ID is not great so the runtime is not saturated.
The solution approach:
Run aggregator for 1 minute while using customerID to assemble messages with the same customer ID into a list
Use Splitter to split the list into individual messages
Send the first message from the splitter to the actual service
Re-route the rest of the list back into the aggregator.
Java DSL version is a bit easier to understand:
final AggregationStrategy aggregationStrategy = AggregationStrategies.flexible(Object.class)
.accumulateInCollection(ArrayList.class);
from("direct:start")
.log("Receiving ${body}")
.aggregate(header("customerID"), aggregationStrategy).completionTimeout(60000)
.log("Aggregate: releasing ${body}")
.split(body())
.choice()
.when(header(Exchange.SPLIT_INDEX).isEqualTo(0))
.log("*** Processing: ${body}")
.to("mock:result")
.otherwise()
.to("seda:delay")
.endChoice();
from("seda:delay")
.delay(0)
.to("direct:start");
Spring XML version looks like the following:
<!-- this is our aggregation strategy defined as a spring bean -->
<!-- see http://stackoverflow.com/questions/27404726/how-does-one-set-the-pick-expression-for-apache-camels-flexibleaggregationstr -->
<bean id="_flexible0" class="org.apache.camel.util.toolbox.FlexibleAggregationStrategy"/>
<bean id="_flexible2" factory-bean="_flexible0" factory-method="accumulateInCollection">
<constructor-arg value="java.util.ArrayList" />
</bean>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<log message="Receiving ${body}"/>
<aggregate strategyRef="_flexible2" completionTimeout="60000" >
<correlationExpression>
<xpath>/order/#customerID</xpath>
</correlationExpression>
<log message="Aggregate: releasing ${body}"/>
<split>
<simple>${body}</simple>
<choice>
<when>
<simple>${header.CamelSplitIndex} == 0</simple>
<log message="*** Processing: ${body}"/>
<to uri="mock:result"/>
</when>
<otherwise>
<log message="--- Delaying: ${body}"/>
<to uri="seda:delay" />
</otherwise>
</choice>
</split>
</aggregate>
</route>
<route>
<from uri="seda:delay"/>
<to uri="direct:start"/>
</route>
</camelContext>

Resources