Please help me on this logic. I have to call the service and get the response back.If the service is down or something have to retry 3 times and once exhausted need to log in DLQ.I'm using until successful processor.For success scenario i'm getting only null payload in logger.But i tried keeping the HTTP outbound end point without until successfull able to get the response from the service. Please find my xml config.
<flow name="Flow" doc:name="eFlow" tracking:enable-default-events="true">
<wmq:inbound-endpoint queue="InputQ" tracking:enable-default-events="true" connector ref="WMQ_Connector" doc:name="connector">
<wmq:transaction action="NONE"/>
</wmq:inbound-endpoint>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<set-session-variable variableName="originalPayload" value="#[payload]" doc:name="Store_Payload"/>
<choice tracking:enable-default-events="true" doc:name="Choice">
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Master']">
<data-mapper:transform config-ref="Master_grf" doc:name="Master"/>
</when>
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Request']">
<data-mapper:transform config-ref="Request_grf" doc:name="Bulk"/>
</when>
<otherwise>
<scripting:component doc:name="Throw_Exception">
<scripting:script engine="Groovy"><![CDATA[throw new IllegalArgumentException ('requests invalid') ]]>
</otherwise>
</choice>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<flow-ref name="Invoke_Service" doc:name="Flow Reference"/>
</flow>
<flow name="Invoke_Service" doc:name="Invoke_Service" tracking:enable-default-events="true">
<cxf:jaxws-client enableMuleSoapHeaders="true" doc:name="SOAP" operation="Request" serviceClass="com.valid.ICase"/>
<until-successful objectStore-ref="objectStore" maxRetries="3" secondsBetweenRetries="2" deadLetterQueue-ref="VM" doc:name="UntilSuccessful_SymboticService">
<http:outbound-endpoint exchange-pattern="request-response" method="POST" doc:name="HTTP" address="http://localhost:1112/symbotic"/>
</until-successful>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger message="**********success***Payload: #[payload]*****" level="INFO" doc:name="Logger"/>
But incase of failure scenario until success retry 3 times ( works fine). I have tried request reply processor inside until also transactional processor. It is not working. Using Mule version 3.4.kindly suggest me.
Retried the same with request -reply processor as per the suggestion
<flow name="Flow" doc:name="eFlow" tracking:enable-default-events="true">
<wmq:inbound-endpoint queue="InputQ" tracking:enable-default-events="true" connector- ref="WMQ_Connector" doc:name="connector">
<wmq:transaction action="NONE"/>
</wmq:inbound-endpoint>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<set-session-variable variableName="originalPayload" value="#[payload]" doc:name="Store_Payload"/>
<choice tracking:enable-default-events="true" doc:name="Choice">
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Master']">
<data-mapper:transform config-ref="Master_grf" doc:name="Master"/>
</when>
<when expression="#[xpath('fn:local-name(/root/*[2])') == 'Request']">
<data-mapper:transform config-ref="Request_grf" doc:name="Bulk"/>
</when>
<otherwise>
<scripting:component doc:name="Throw_Exception">
<scripting:script engine="Groovy"><![CDATA[throw new IllegalArgumentException('requests other then Master andRequest') ]]>
</otherwise>
</choice>
<mulexml:dom-to-xml-transformer></mulexml:dom-to-xml-transformer>
<request-reply timeout="10000">
<vm:outbound-endpoint path="request"/>
<vm:inbound-endpoint path="reply"/>
</request-reply>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger message="**********success***Payload: #[payload]*****" level="INFO" doc:name="Logger"/>
</flow>
<flow name="Invoke_Service" doc:name="Invoke_Service" tracking:enable-default-events="true">
<vm:inbound-endpoint path="request" doc:name="VM"/>
<cxf:jaxws-client enableMuleSoapHeaders="true" doc:name="SOAP" operation="Request" serviceClass="com.valid.ICase"/>
<until-successful objectStore-ref="objectStore" maxRetries="3" secondsBetweenRetries="2" deadLetterQueue-ref="VM" doc:name="UntilSuccessful_Service">
<http:outbound-endpoint exchange-pattern="request-response" method="POST" doc:name="HTTP" address="http://localhost:1112/symbotic"/>
</until-successful>
</flow>
Even then getting the null payload. Kindly suggest is this is the way your were directing me. Please correct me if im wrong.
until-successful is an asynchronous processor. It does not return response from service call.
Success or failure are defined as:
If the child message processor throws an exception, this is a failure.
If the child message processor does not return a message (e.g. is a one-way endpoint), this is a success.
If a 'failure expression' (see below) has been configured, the return message is evaluated against this expression to determine failure or not.
Otherwise:
If the child message processor returns a message that contains an exception payload, this is a failure.
If the child message processor returns a message that does not contain an exception payload, this is a success.
http://www.mulesoft.org/documentation/display/current/Routing+Message+Processors#RoutingMessageProcessors-UntilSuccessful
Related
I have a mule flow(mock-flow) that currently makes http calls to a couple of microservices. If one of the service calls fails due to a connection exception, i have a rollback exception strategy configured to reprocess the message (sending to kafka which in turn invokes the mock flow)but the retry seems to be happening indefinitely inspite of specifying a maxRedeliveryAttempts attribute. How do I limit the no of retries? Any help would be greatly appreciated
<flow name="mock-flow">
<logger level="INFO" message="CRD::: Calling Selldown settle Micro Service***"/>
<logger message="CRD::: Response received : #[message.payload]" level="INFO" />
<http:request config-ref="tp-ins-selldown-msConfig" path="/settle"
method="POST" doc:name="HTTP">
<http:success-status-code-validator
values="200,201" />
</http:request>
<http:request parseResponse="false" config-ref="tp-ins-limits-msConfig" path="booksdlimit"
method="POST" doc:name="HTTP">
<http:success-status-code-validator values="200,201"/>
</http:request>
<choice-exception-strategy doc:name="Choice Exception Strategy">
<rollback-exception-strategy when="exception.causedBy(java.net.ConnectException)" maxRedeliveryAttempts="2" doc:name="Rollback Exception Strategy">
<logger message="Will attempt redelivery" level="INFO" doc:name="Logger" />
<vm:outbound-endpoint exchange-pattern="one-way" path="kafka.inpath" doc:name="VM" />
<on-redelivery-attempts-exceeded>
<logger message="redelivery attempt exceeded" level="INFO" doc:name="Logger" />
<logger message="Retry exhausted" level="INFO" doc:name="Logger" />
</on-redelivery-attempts-exceeded>
</rollback-exception-strategy>
</choice-exception-strategy>
Since the maxReDeliveryAttempts attrtibute wasn't working(for whatever weird reason), I had to do it on my own(manually) by configuring a mule object store with the message request as the key and retry counter as the value.
<rollback-exception-strategy when="exception.causedBy(java.net.ConnectException)" doc:name="Rollback Exception Strategy">
<objectstore:retrieve config-ref="ObjectStore" key="#[uuid]" targetProperty="retryCounter" doc:name="Get value from ObjectStore" />
<logger level="INFO" doc:name="Logger" message="Retry counter --------------> #[retryCounter]"/>
<choice doc:name="Choice">
<when expression="#[retryCounter > 3]">
<logger message="Retry exhausted" level="INFO" doc:name="Logger" />
<objectstore:remove key="#[uuid]" config-ref="ObjectStore" ignoreNotExists="true" doc:name="Remove the key after retry exhaust" />
</when>
<otherwise>
<expression-component>
Thread.sleep(3000);
</expression-component>
<logger message="Will attempt redelivery" level="INFO" doc:name="Logger" />
<transformer ref="ObjectToString"/>
<vm:outbound-endpoint exchange-pattern="one-way" path="kafka.inpath" doc:name="VM" />
<objectstore:remove key="#[uuid]" config-ref="ObjectStore" ignoreNotExists="true" doc:name="Remove if exists" />
<objectstore:store config-ref="ObjectStore" key="#[uuid]" value-ref="#[retryCounter + 1]" doc:name="Store new value" />
</otherwise>
</choice>
</rollback-exception-strategy>
Seems even if maxRedeliveryAttempts variable had worked, it might not have helped my use case since when multiple requests are triggered, there is no way we would ensure that every request was retriggered only 3 times by simply relying on this attribute(unless mule internally uses a hashcode for every req to determine if it has already been retriggered or not)
Also flow variables and session variables didn't work in my case since the retrigger point was a kafka queue (which wasn't manually invoked by flow-ref). Hence had to use an object store
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.
I have a scenario like below,
Inbound Queue called 'InQ'(Synchronous) which will have messages each with messageHeader JMSXGroupID(Example A or B Or C).Based on the JMSXGroupId header i will route to clientA or ClientB or ClientC.
SomeTime If ClientA takes longer Time to respond. I don't want to take the otherMessages in Queue InQ' which haveJMSXGroupID=A`.Once the response is back, i need to process the other messages in Order.
I did implemented Client Ack Transaction.But in this cases if i'm waiting for the response from ClientA, other messages with JMXGroupId B and C also seems to be waiting.Which means it looking by overall one by one(FIFO) which i don't want to do.
Not sure how to implement FIFO based on JMSXGroupID. Any thoughts and Ideas will be helpful. Thanks in advance.
<jms:activemq-connector name="Active_MQ" username="....." password="..." brokerURL="...." validateConnections="true" doc:name="Active MQ" numberOfConsumers="1" maxRedelivery="-1" disableTemporaryReplyToDestinations="true" persistentDelivery="true"/>
<flow name="testFlow">
<jms:inbound-endpoint connector-ref="Active_MQ" doc:name="JMS" queue="InQ" exchange-pattern="request-response">
<jms:client-ack-transaction action="ALWAYS_BEGIN"/>
</jms:inbound-endpoint>
<logger level="INFO" doc:name="Logger" message="**testCheck#[payload]"/>
<choice doc:name="Choice">
<when expression="#[message.inboundProperties.JMSXGroupId=='A']">
<logger level="INFO" doc:name="Logger" message="***first***"/>
<flow-ref name="ClientA" doc:name="ClientA"/>
</when>
<when expression="#[message.inboundProperties.JMSXGroupId=='B']">
<flow-ref name="ClientB" doc:name="ClientB"/>
</when>
<when expression="#[message.inboundProperties.JMSXGroupId=='C']">
<flow-ref name="ClientC" doc:name="ClientC"/>
</when>
<otherwise>
<logger level="INFO" doc:name=" Other Logger"/>
</otherwise>
</choice>
</flow>
Edit1: Made all the 3 , listening to the same Queue.
<composite-source doc:name="Composite Source">
<jms:inbound-endpoint connector-ref="Active_MQ" doc:name="JMS" queue="InQ">
<jms:selector expression="JMSXGroupID=A"/>
</jms:inbound-endpoint>
<jms:inbound-endpoint connector-ref="Active_MQ" doc:name="JMS" queue="InQ">
<jms:selector expression="JMSXGroupID=B"/>
</jms:inbound-endpoint>
<jms:inbound-endpoint connector-ref="Active_MQ" doc:name="JMS" queue="InQ">
<jms:selector expression="JMSXGroupID=C"/>
</jms:inbound-endpoint>
</composite-source>
It does thrown the error There is already a listener registered on this connector on endpointUri: jms://InQ.
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.
I have a sub-flow to invoke a soap service (req:String , response:String)
<sub-flow name="vinculaValidaServiceClienteFlow" doc:name="vinculaValidaServiceClienteFlow">
<cxf:jaxws-client operation="vinculaServicioIngreso" serviceClass="...VinculaValidaService" doc:name="SOAP"/>
<http:outbound-endpoint exchange-pattern="request-response" method="POST" address="http://localhost:8070/pic/vinculaValidaService" doc:name="HTTP"/>
</sub-flow>
I have a simple service that I'm calling from a test flow. This service can be invoked well with MuleClient:
<flow name="vinculacionFlow2" doc:name="vinculacionFlow2">
<vm:inbound-endpoint exchange-pattern="request-response" path="test2" doc:name="VM"/>
<logger level="INFO" doc:name="Logger"/>
<flow-ref name="vinculaValidaServiceClienteFlow" doc:name="Flow Reference"/>
</flow>
When I include the flow-ref in a main flow, can not be invoked, although the unit test was successful.
<flow name="vinculaServiceFlow" doc:name="vinculaServiceFlow">
<http:inbound-endpoint exchange-pattern="request-response" doc:name="vinculaServiceHTTP" ref="vinculaServiceHTTPEndpoint"/>
<logger level="INFO" doc:name="Logger" message="luna es #[payload]"/>
<cxf:jaxws-service doc:name="vinculaServiceSOAP" serviceClass="...service.VinculaService"/>
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger message="marte es #[payload]" level="INFO" doc:name="printpayload"/>
<set-variable variableName="cedula" value="#[message.payload]" doc:name="Variable"/>
<logger message="jupiter es #[flowVars['cedula']]" level="INFO" doc:name="printVar"/>
<set-payload value="#[message.payloadAs(java.lang.String)]" doc:name="Set Payload"/>
<logger message="sol es #[payload]" level="INFO" doc:name="printpayload"/>
<flow-ref name="vinculaValidaServiceClienteFlow" doc:name="Flow Reference"/>
<scripting:transformer doc:name="Groovy">
<scripting:script engine="Groovy"><![CDATA[import ec.gob.presidencia.tecnologia.pic.vincula.service.VinculaResponse def responseVincula = new VinculaResponse("54545366644","12063139", "se puede vincular") return responseVincula ]]>
</scripting:script>
</scripting:transformer>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<set-payload value="Error durante el procesamiento del servicio de vinculacion" doc:name="Set mensejae error"/>
</catch-exception-strategy>
</flow>
The resulting exception is:
Exception stack is:
1. java.lang.reflect.Method cannot be cast to java.lang.String(java.lang.ClassCastException)
org.mule.module.cxf.CxfOutboundMessageProcessor:338 (null)
2. java.lang.reflect.Method cannot be cast to java.lang.String. Failed to route event via endpoint: org.mule.module.cxf.CxfOutboundMessageProcessor. Message payload is of type: String (org.mule.api.transport.DispatchException)
org.mule.module.cxf.CxfOutboundMessageProcessor:150 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transport/DispatchException.html)
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to service.VinculaResponse
at ec.gob.presidencia.tecnologia.pic.vincula.service.jaxws_asm.VinculaServicioIngresoResponse_WrapperTypeHelper1.createWrapperObject(Unknown Source)
at org.apache.cxf.jaxws.interceptors.WrapperClassOutInterceptor.handleMessage(WrapperClassOutInterceptor.java:100)
... 97 more
This exception can not understand it, since the payload into a string before invoking the service (flow-ref). Could give me an idea to identify where this point at correcting?
Thanks.
Could be a duplicate of this? Mule method cannot be cast to string
You might also want to consider using proxying if your purpose is to map inbound SOAP calls to outbound SOAP calls: http://www.mulesoft.org/documentation/display/current/Proxying+Web+Services+with+CXF