I want to trigger a long operation using camel rest call. Since, the operation takes significant amount of time, the request will get timeout and show an error message on client side. I don't want this to happen.
So, I am trying to solve this problem using a queue as follows:
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="tcp://0.0.0.0:61616" />
<property name="userName" value="admin"/>
<property name="password" value="admin"/>
</bean>
<camelContext xmlns="http://camel.apache.org/schema/blueprint" trace="true">
<route>
<from uri="cxfrs:bean:rsprovider" />
<setBody>
<simple>${header.operationName}</simple>
</setBody>
<to uri="activemq:queue:myqueue"/>
<!-- Send immediate response to client as, the processing will take a while -->
<setBody>
<simple>Received feeder service request to ${header.operationName}. Request will be processed soon.</simple>
</setBody>
</route>
<route>
<from uri="activemq:queue:myqueue"/>
<convertBodyTo type="java.lang.String"/>
<recipientList>
<simple>direct-vm:operation-${body}</simple>
</recipientList>
</route>
</camelContext>
But, it seems that adding to a queue is synchronous and the response is not received on time. How can I make this queue asynchronous? I tried appending ?jms.useAsyncSend=true to the queue url. But that didn't work.
You should try asyncConsumer
<from uri="activemq:queue:myqueue?asyncConsumer=true"/>
Camel 2.9: Whether the JmsConsumer processes the Exchange
asynchronously. If enabled then the JmsConsumer may pickup the next
message from the JMS queue, while the previous message is being
processed asynchronously (by the Asynchronous Routing Engine). This
means that messages may be processed not 100% strictly in order. If
disabled (as default) then the Exchange is fully processed before the
JmsConsumer will pickup the next message from the JMS queue. Note: if
transacted has been enabled, then asyncConsumer=true does not run
asynchronously, as transactions must be executed synchronously (Camel
3.0 may support asynchronous transactions).
Also check the Async Request Reply APIs
http://camel.apache.org/async.html
Future<Object> future = template.asyncRequestBody("activemq:queue:myqueue", "<YOUR_MESSAGE>");
Related
I have the scenario below.
Request Web Services from client system. This request is that the file will be copied.
Receive request by cxf component in application.
Response the return code that means success after receiving request immediately.
After send response, the application will fetch the file.
So, I implemented route.
<route>
<from uri="cxf:bean:FileTransferServiceEndPoint"/>
<multicast parellelProcessing="true">
<toD uri="direct:bean"/>
<toD uri="direct:fetchFile"/>
</multicast>
</route>
<route>
<from uri="direct:bean"/>
<bean method="process" ref="returnMsg"/>
<end>
</route>
<route>
<from uri="direct:fetchFile"/>
<pollEnrich>
<simple>file:/test/inBox</simple>
</pollEnrich>
<toD uri="file:/test/outBox"/>
</route>
I faced to have some problem.
Originally, I think that response will be return by returnMsg Bean.
But Response Message was not respond until the file is completely processed.
I want the message delivered immediately to the client. And at the same time, I want the files to be processed.
How should I implement a route to fulfill my scenario?
Please let me know this solution.
Thank you.
Consider using SEDA component (take a look at the option waitForTaskToComplete) or WireTap EIP (it makes a "lite" copy of the message but you can customize its behavior) to fetch the file.
PS 1.: Caution with the usage of pollEnrich without setting a timeout.
PS 2.: Depending upon the way you receive the body message, you may face a stream closed issue by using it more than once, as you end up doing in multicast.
If you want your "direct" routes to be executed independently of each other, consider to use wireTap
<route>
<from uri="cxf:bean:FileTransferServiceEndPoint"/>
<wireTap uri="direct:bean"/>
<to uri="direct:fetchFile"/>
</route>
from the "Camel in Action" book:
By using the wireTap method in the Java DSL, you can send a copy of the exchange
to a secondary destination without affecting the behavior of the rest of the route
I have created route that accept request from multiple producers and send to a remote server by using netty4 with request-response. However, when camel is sending a request to remote server and waiting for response, next incoming request is received and want to send to remote server but got IOException as camel cannot receive response.
So, how to set Camel-Netty4 send request and wait for response before send next.
The route configuration:
from("direct:DirectProcessOut?block=true")
.to("netty4:tcp://192.168.1.2:8000?sync=true&synchronous=true&reuseChannel=true")
I actually ran into a similar issue trying to send out several messages at a time based on rows in a database table. The calls wouldn't wait for each other to complete and essentially stepped on each other and either hung or blew up.
The solution I eventually found was to use a message queue. Take in your requests and route them into a single activemq route.
So something like:
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route>
<from uri="direct:direct:DirectProcessOut"/>
<to uri="activemq://processOutQueue"/>
</route>
</camelContext>
<camelContext xmlns="http://camel.apache.org/schema/blueprint">
<route>
<from uri="activemq://processOutQueue"/>
<to uri="netty4:tcp://192.168.1.2:8000?sync=true&synchronous=true&reuseChannel=true"/>
</route>
</camelContext>
My case was a little different, so I'm not sure if this will preserve your message you want to send. But hopefully it gives you a place to start.
I can see that many Camel route examples are initiated with a "direct" component. For example:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="myroute">
<from uri="direct:start"/>
<setBody>
<simple>Hello World!</simple>
</setBody>
<log message="${body}"/>
<to uri="mock:result"/>
</route>
</camelContext>
However, by running a route like this (mvn camel:run) the route is not started and Camel keeps hanging forever. Is it not meant to be used directly this kind the direct component?
Thanks
Its not hanging. You need to send a message to the direct endpoint before its routed. eg like in java code to do a direct method invocation from a client by calling a java method.
Instead of direct you can use a timer if you want to route a message automatic every X time etc.
To send a message to the direct endpoint (or any other Camel endpoint) then read about the producer template. For example from the getting started guide: http://camel.apache.org/walk-through-an-example.html
I'm using camel to route from SOAP web service to Rest Service. My route is like following.
SOAP Service --> Processor A --> Rest --> Processor B .
I'm using Exchange pattern and Rest is hosted in Jboss Server. My problem is how to get Rest Response ( json string ). When i get in message in Processor B it contains the output message or processor A.
<camelContext xmlns="http://camel.apache.org/schema/spring" trace="true">
<route>
<from uri="cxf:bean:serviceA"/>
<process ref="processorA" />
<to uri="cxfrs:bean:serviceRest"/>
<process ref="processorB"/>
</route>
</camelContxt>
I'm new to camel. any help would be appreciated.
You should be able to the REST response in the proxessorB by referencing the exchange in message.
Finally found the answer with the help of friends. It was error in fasterxml jason provider. I changed the json provider to codehaus
<cxf:rsClient id="serviceRest" address="http://localhost:8080/rest-test/rest"
serviceClass="org.apache.cxf.jaxrs.client.WebClient" loggingFeatureEnabled="true" >
<cxf:providers>
<ref bean="jasonProvider"/>
</cxf:providers>
</cxf:rsClient>
<bean id="jasonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
Now i have the json response in exchange.
I set up a route between two CXF endpoints up like this:
<cxf:cxfEndpoint id="monitoringService"
address="${esb.monitoring-service.ep.address}" serviceName="s:monitoring-service"
endpointName="s:portSOAP" wsdlURL="classpath:/webservices/monitoring-service.wsdl"
xmlns:s="http://xyz/monitoring/"
/>
<endpoint
id="originMonitoringService"
uri="${origin.monitoring-service.ep.address}" />
<route>
<from uri="cxf:bean:monitoringService?dataFormat=MESSAGE" />
<to ref="originMonitoringService" />
</route>
However when there are SOAP faults happening at the 'originMonitoringService' then they seem not to be forwarded to the endpoint published by Camel and as such do not reach the client that is connecting to it.
How am I supposed to declare this connection?
(Just FYI: ${xx}-style variable are properly replaced with values like http://somehost/someservice at runtime.)
This issue should be fixed by CAMEL-4570