Mule async request-reply - mule

I actually invoke an exe with the expression-component through a http-request on port 8081. The exe sends a http-request on port 8082 and I'm able to log the output.
Finally i have to send the output of the reply-flow back to the main-flow but i dont know how...
Here is my code:
<flow name="mainFlow" doc:name="mainFlow">
<http:inbound-endpoint exchange-pattern="request-response" address="http://localhost:8081" doc:name="HTTP" />
<request-reply timeout="10000">
<vm:outbound-endpoint path="request" exchange-pattern="one-way"/>
<vm:inbound-endpoint path="reply" exchange-pattern="one-way"/>
</request-reply>
</flow>
<flow name="request" doc:name="request">
<vm:inbound-endpoint path="request" doc:name="VM" />
<expression-component doc:name="Expression">Runtime.getRuntime().exec("C:\\myfile.exe arg1");</expression-component>
</flow>
<flow name="reply" doc:name="reply">
<http:inbound-endpoint address="http://localhost:8082" doc:name="HTTP" exchange-pattern="one-way" />
<logger message="#[message.inboundProperties['test']]" level="INFO" doc:name="Logger"/>
<vm:outbound-endpoint path="reply" doc:name="VM" exchange-pattern="one-way"/>
</flow>

You have to make sure you are carrying the MULE_CORRELATION_ID message property through the exe down to http://localhost:8082 otherwise the request-reply message processor has no way to correlate the asynchronous reply with the current request.
For example, pass the correlation ID has a second argument to the exe:
<expression-component doc:name="Expression">
Runtime.getRuntime().exec("C:\\myfile.exe arg1 " + message.correlationId);
</expression-component>
And make sure the exe propagates the correlation ID towards http://localhost:8082 in an HTTP header named X-MULE_CORRELATION_ID.

Related

Until-Successful Process for list of objects in a long running query not working

I want to develop a flow that could allow me to make queries to an external system that could take a long time to return. I may have to make queries for multiple values in a list. I am using an until-successful scope in solving the problem. Unfortunately, the even though the request is run several times, the failed records never get put in the dead letter queue. Here is my attempt at solving the problem:
<!-- Dead Letter Queue for exhausted attempts-->
<vm:endpoint name="DLQ" path="DLQ_VM" doc:name="VM"/>
<flow name="StartFlow" processingStrategy="synchronous">
<!--Place a list of String errors to query for on this vm -->
<vm:inbound-endpoint path="request-processing-queue" "
exchange-pattern="one-way" doc:name="VM"/>
<vm:outbound-endpoint path="reprocessing-queue"
exchange-pattern="request-response" doc:name="VM"/>
<logger level="INFO" message="Data returned is #[payload]"/>
<catch-exception-strategy>
<logger level="ERROR" message="Failure During Processing"/>
</catch-exception-strategy>
</flow>
<flow name="RetryingProcess">
<vm:inbound-endpoint name="reprocessing-vm" exchange-
pattern="request-response"
path="reprocessing-queue" doc:name="VM"/>
<foreach collection="#[payload]" doc:name="For Each">
<vm:outbound-endpoint path="by-singles-vm" exchange-
pattern="request-response"/>
</foreach>
</flow>
<flow name="query-retry">
<vm:inbound-endpoint path="by-singles-vm" exchange-
pattern="request-response" doc:name="VM"/>
<until-successful objectStore-ref="objectStore"
failureExpression="#[groovy:(exception &&
exception in com.trion.CustomException)
||!(payload instanceof
com.trion.QueryResult])]"
maxRetries="5"
millisBetweenRetries="300000"
deadLetterQueue-ref="DLQ_VM" doc:name="Until
Successful">
<vm:outbound-endpoint path="try-again-vm" exchange-
pattern="request-response" doc:name="VM"/>
</until-successful>
</flow>
<flow name="GetQueryValue" >
<vm:inbound-endpoint path="try-again-vm" exchange-
pattern="request-response" doc:name="VM"/>
<flow-ref name="QueryRequest" />
</flow>
<!-- This never happens, i.e. the results are not put here... after retying
-->
<flow name="AttemptsExceededProcessing">
<inbound-endpoint ref="DLQ_VM" doc:name="Generic"/>
<logger level="DEBUG" message="Entering Final Destination Queue with
payload is #[payload]"/>
</flow>
<!-- Here I have a query to the external system... >
<flow name="QueryRequest">
...... Makes the long running query Here..
//returns com.trion.QueryResult
</flow>
</mule>
Please help!
There was no problem with the configuration. I had a millisSecondsBetweenRetry value set so small I wasn't seeing the log messages and assumed it wasn't working.

How to use Mule Expression in JMS:selector

I checked several previous discussions but couldnt find the answer.
I am trying to achieve synchronous communicaiton using JMS back-channel (http://www.whishworks.com/blog/synchronous-communication-using-jms-back-channel). Apart from the things mentioned in that site, I need to filter out the message from the inbound queue based on a dynamic Id.
Following are my mule flows:
<flow name="serverFlow" >
<jms:inbound-endpoint doc:name="REQUEST" queue="REQUEST.QUEUE" connector-ref="jmsConnector">
<jms:selector expression="MULE_CORRELATION_ID='#[sessionVars.myCorrelationId]'"/>
</jms:inbound-endpoint>
<set-payload value="#[payload] + Hello World from Receiver" doc:name="Set Payload" />
<jms:outbound-endpoint doc:name="REPLY" queue="REPLY.QUEUE" connector-ref="jmsConnector" />
</flow>
<flow name="mainFlow" >
<http:listener config-ref="HTTP_Listener_Configuration" path="/jms" allowedMethods="GET" doc:name="HTTP"/>
<set-session-variable variableName="myCorrelationId" value="#[System.currentTimeMillis().toString()]" doc:name="Set Correlation ID"/>
<set-payload value="New message sent from Mule - mainFlow at #[new Date()]" doc:name="Set Message"/>
<set-property propertyName="MULE_CORRELATION_ID" value="#[sessionVars.myCorrelationId]" doc:name="Property"/>
<request-reply doc:name="Request-Reply">
<jms:outbound-endpoint doc:name="REQUEST" connector-ref="jmsConnector" queue="REQUEST.QUEUE"/>
<jms:inbound-endpoint doc:name="REPLY" connector-ref="jmsConnector" queue="REPLY.QUEUE"/>
</request-reply>
<logger message="Reply to sender: #[message]" level="WARN" doc:name="Logger" />
</flow>
If I try a static value like "<jms:selector expression="MULE_CORRELATION_ID='12345'"/>", it works. But if I try a dynamic ID using MEL, its not working. The MEL inside the jms selector expression is not working. The message stays at the queue as Unread. I used logs to see what the MULE_CORRELATION_ID is while being set at mainFlow and found the same value is set in the message that is UNREAD in the queue. So, I guess nothing is wrong in the way the MULE_CORRELATION_ID is set. The only problem is that MEL is not working within jms:selector.
Could you please help how to get MEL working within JMS selector?
Thank you very much.
MEL is working fine in the selector but its usage is very limited. When the JMS selector is created, there's no in-flight event available to Mule so none of the event-bound data (including session) is available.
To select a very particular message, you need to use a JMS message requester, constructed with the desired selector, like:
jms://REQUEST.QUEUE?selector=MULE_CORRELATION_ID%3D'#[sessionVars.myCorrelationId]'
Here is the working solution based on David's suggestion. I am using wmq here (not jms).
<mulerequester:config name="Mule_Requester" doc:name="Mule Requester"/>
<flow name="mainFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/test" allowedMethods="GET" doc:name="HTTP"/>
<set-payload value="My Message" doc:name="Set Message"/>
<set-property propertyName="JMSCorrelationID" value="12345" doc:name="Property"/>
<set-session-variable variableName="myCorrelationId" value="ID:313233343500000000000000000000000000000000000000" doc:name="Set Correlation ID"/>
<!--313233343500000000000000000000000000000000000000 is the MQMD CorrelationId for 12345. This is set by IBM MQ -->
<logger message="The Message to REQUEST QUEUE: #[message]" level="WARN" doc:name="Logger"/>
<wmq:outbound-endpoint queue="REQUEST.QUEUE" connector-ref="wmqConnector" doc:name="OUT"/>
<mulerequester:request config-ref="Mule_Requester" resource="wmq://REPLY.QUEUE?selector=JMSCorrelationID%3D'#[sessionVars.myCorrelationId]'" doc:name="Mule Requester" timeout="120000"/>
<logger message="Final Response: #[message]" level="WARN" doc:name="Logger"/>
</flow>
Please note, I manually moved the message from Request queue to Reply queue using MQVE for my testing. In real time, it will be done by another program.

Using a enricher on a Mule outbound endpoint so that the message properties context is not lost

When i make a call to to soap web service using the soap component in Mule. The message properties context is lost. I understand a Mule enricher component can be used but not sure on the usage. Below you will find my test mule code
<spring:beans>
<spring:bean id="myWebServiceImpl" class="com.xxx.xxx.service.MyWebServiceImpl">
</spring:bean>
</spring:beans>
<custom-transformer class="com.xxx.xxx.service.TestTransformer" name="Java" doc:name="Java"/>
<flow name="testwebserviceFlow1" doc:name="testwebserviceFlow1">
<file:inbound-endpoint path="c:\landing" responseTimeout="10000" doc:name="File"/>
<object-to-string-transformer doc:name="Object to String"/>
<http:outbound-endpoint exchange-pattern="request-response" method="POST" address="http://localhost:28081/MyWebService" responseTimeout="100000" doc:name="HTTP" >
<cxf:jaxws-client operation="helloWorld" serviceClass="com.xxx.xxx.service.MyWebService" enableMuleSoapHeaders="true" doc:name="SOAP"/>
</http:outbound-endpoint>
<transformer ref="Java" doc:name="Transformer Reference"/>
<logger level="INFO" doc:name="Logger"/>
</flow>
<flow name="MyWebServiceFlow" doc:name="MyWebServiceFlow">
<http:inbound-endpoint exchange-pattern="request-response" address="http://localhost:28081/MyWebService?wsdl" doc:name="HTTP" responseTimeout="100000">
<cxf:jaxws-service serviceClass="com.xxx.xxx.service.MyWebService" doc:name="SOAP"/>
</http:inbound-endpoint>
<component doc:name="MyWebService">
<spring-object bean="myWebServiceImpl"/>
</component>
</flow>
Yes, you can use an enricher to preserve your original message and put the return value of the web service into a variable. It works like this:
<enricher source="#[payload]" target="#[variable:myVal]">
<http:outbound-endpoint exchange-pattern="request-response" method="POST" address="http://localhost:28081/MyWebService" responseTimeout="100000" doc:name="HTTP" >
<cxf:jaxws-client operation="helloWorld" serviceClass="com.xxx.xxx.service.MyWebService" enableMuleSoapHeaders="true" doc:name="SOAP"/>
</http:outbound-endpoint>
</enricher>
You can then later access the variable like this:
<logger message="#[variable:myVal]" level="INFO"/>
If you just want to call the web service and ignore any return values, you can also do that asynchronously by putting the http outbound inside <async></async> tags instead of the enricher.

How to implement deadLetterQueue for JDBC Connector Using Until Successful

I am trying implement deadLetterQueue on UntilSuccessful for JDBC Connector. I would like to send the payload to a queue(DeadLetterQueue) when UntilSuccessful fails after trying no of times as configured. I referred following links
http://blogs.mulesoft.org/meet-until-successful-store-and-forward-for-mule/
Where in the application would you define the vm:endpoint for a dlqEndpoint-ref defined in an until-successful scope?
Below is my code snippet
<vm:endpoint exchange-pattern="one-way" path="dlqChannel" name="VM" doc:name="VM"/>
Above line is my global element
<flow...> .... <until-successful objectStore-ref="objectStore" deadLetterQueue-ref="dlqChannel" maxRetries="5" secondsBetweenRetries="60" doc:name="Until Successful" failureExpression="exception-type:java.sql.SQLException">
<jdbc-ee:outbound-endpoint exchange-pattern="request-response" queryKey="Insert Query" queryTimeout="-1" connector-ref="Database" doc:name="Database"/>
</until-successful>....</flow>
<flow name="Flow2" doc:name="Flow2">
<endpoint ref="dlqChannel" />
<logger message="DEAD DEAD DEAD LETTER LETTER LETTER #[message]" level="INFO" doc:name="Logger"/>
</flow>
At this line <endpoint ref="dlqChannel" /> I am getting compile error says "Reference to unknown global element:dlqChannel"
Can any one suggest a best way to achieve this scenario.
Thanks,
Kalyan
Your endpoint is called 'VM' not 'dlqChannel'. Change either the name to dlqChannel or point it to VM.
This issue is resolved.
Below is my code snippet.
<vm:endpoint exchange-pattern="one-way" path="dlq" name="dlqChannel" doc:name="VM"/>
Above line is vm global element
<flow...> ... <until-successful objectStore-ref="objectStore" deadLetterQueue-ref="dlqChannel" maxRetries="2" secondsBetweenRetries="10" doc:name="Until Successful" failureExpression="exception-type:java.sql.SQLException">
<jdbc-ee:outbound-endpoint exchange-pattern="request-response" queryKey="Insert Query" queryTimeout="-1" connector-ref="Database" doc:name="Database"/>
</until-successful>
....
</flow>
<flow name="Flow2" doc:name="Flow2">
<vm:inbound-endpoint exchange-pattern="one-way" path="dlq" doc:name="VM"/>
<logger message="DEAD DEAD DEAD LETTER LETTER LETTER #[message.payload]" level="INFO" doc:name="Logger"/>
</flow>
Based on "deadLetterQueue-ref" in UntilSuccessful, payload goes to vm:inbound-endpoint(vm://dlq) as defined in the vm global endpoint.
As Seba correctly points out, your error is due to a wrong name/ref. As for how to implement the deadLetterQueue, you need an inbound endpoint. So in Flow2, change the endpoint to <inbound-endpoint ref="dlqChannel" />.

Where in the application would you define the vm:endpoint for a dlqEndpoint-ref defined in an until-successful scope?

I'm trying to follow the example in this blog post (http://blogs.mulesoft.org/meet-until-successful-store-and-forward-for-mule/) for defining a dead letter queue for an until-successful scope element. This is the snippet from the blog post that doesn't quite make sense:
<vm:endpoint name="dlqChannel" path="dlq" />
<until-successful objectStore-ref="objectStore"
dlqEndpoint-ref="dlqChannel"
maxRetries="3"
secondsBetweenRetries="10">
...
</until-successful>
I don't quite understand where the vm endpoint lives in the app. I don't think it goes in the same flow as the until-successful element. I've tried putting it in its own flow but I get a NoSuchBeanDefinitionException.
Here is my relevant code:
<flow ....>
....
<until-successful objectStore-ref="objectStore" failureExpression="#[header:INBOUND:http.status != 201]" maxRetries="1" secondsBetweenRetries="5" doc:name="Until Successful" deadLetterQueue-ref="aggieFeedDestinedDeadLetterQueue">
....
</flow>
<flow name="edus-pubFlow1" doc:name="edus-pubFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="aggieFeedDestinedDeadLetterQueue" doc:name="aggieFeedDestinedDeadLetterQueue"/>
<logger message="DEAD DEAD DEAD LETTER LETTER LETTER #[message]" level="INFO" doc:name="Logger"/>
</flow>
The dlqChannel attribute refers to a global endpoint. In your case, use:
<vm:inbound-endpoint exchange-pattern="one-way" path="aggieFeedDestinedDeadLetterQueue" />
<flow ....>
....
<until-successful objectStore-ref="objectStore"
failureExpression="#[header:INBOUND:http.status != 201]"
maxRetries="1" secondsBetweenRetries="5"
deadLetterQueue-ref="aggieFeedDestinedDeadLetterQueue">
....
</flow>
<flow name="edus-pubFlow1">
<endpoint ref="aggieFeedDestinedDeadLetterQueue" />
<logger message="DEAD DEAD DEAD LETTER LETTER LETTER #[message]" level="INFO" doc:name="Logger"/>
</flow>
Also if you're using Mule 3.3.0 or above, you can use MEL:
failureExpression="#[message.inboundProperties['http.status'] != 201]"