I am stuck up with a problem with the request-reply router in mule. I am using the mule release 3.4.0. The request-reply is used in a fork-join pattern , i followed this article on the blog site http://blogs.mulesoft.org/aggregation-with-mule-fork-and-join-pattern/.
<request-reply>
<all enableCorrelation="ALWAYS">
<vm:outbound-endpoint path="PathA"/>
<vm:outbound-endpoint path="PathB"/>
</all>
<vm:inbound-endpoint path="FinalResponse">
<message-properties-transformer>
<add-message-property key="MULE_CORRELATION_GROUP_SIZE" value="2" />
</message-properties-transformer>
<collection-aggregator />
</vm:inbound-endpoint>
</request-reply>
The issue that i face is the processor placed after the request-reply is not reached.In mule i see 2 responses been sent to the FinalResponse vm endpoint. I tried placing my own custom aggregator in place of the collection-aggregator. But this is not reached. I am not sure how i can debug this issue. Please note that i have 2 such request-reply routers in two flows. Can someone help on this.
Adding the mule configuration. For abbrevity attaching only the parent flow and one of the child flow
ParentFlow
<flow name="ParentFlow" doc:name="ParentFlow" tracking:enable-default-events="true">
<file:inbound-endpoint path="${SourceFilePath}"
connector-ref="ParentFlowInboundConnector"
responseTimeout="10000" tracking:enable-default-events="true">
<file:filename-regex-filter pattern="${REGEX}" caseSensitive="false"/>
</file:inbound-endpoint>
<object-to-string-transformer doc:name="Object to String"/>
<message-properties-transformer
doc:name="Message Properties">
<add-message-property key="Source_System" value="XXX" />
<add-message-property key="publisherName" value="YYY" />
<add-message-property key="FlowName" value="ZZZ"/>
</message-properties-transformer>
<!-- This would store the message in the db -->
<wire-tap>
<vm:outbound-endpoint path="PERSITENCE.OUT"/>
</wire-tap>
<request-reply>
<all doc:name="Move the message to all endpoints" enableCorrelation="ALWAYS">
<vm:outbound-endpoint path="PathA"/>
<vm:outbound-endpoint path="PathB"/>
<vm:outbound-endpoint path="PathC"/>
<vm:outbound-endpoint path="PathD"/>
</all>
<vm:inbound-endpoint path="Response">
<message-properties-transformer>
<add-message-property key="MULE_CORRELATION_GROUP_SIZE" value="4" />
</message-properties-transformer>
<collection-aggregator failOnTimeout="false" doc:name="Collection Aggregator" />
</vm:inbound-endpoint>
</request-reply>
<component class="ProcessorA" />
<component class="ProcessorB" />
<exception-strategy ref="Exception Strategy" doc:name="Reference Exception Strategy"/>
</flow>
Child Flow
<flow name="PathA" doc:name="PathA">
<vm:inbound-endpoint path="PathA" >
<vm:transaction action="ALWAYS_BEGIN"/>
</vm:inbound-endpoint>
<message-properties-transformer doc:name="Message Properties">
<add-message-property key="originalFilename_processing" value="#[message.inboundProperties.originalFilename]" />
</message-properties-transformer>
<message-properties-transformer doc:name="Message Properties">
<add-message-property key="directory" value="#[message.inboundProperties.directory]" />
</message-properties-transformer>
<message-properties-transformer doc:name="Message Properties">
<add-message-property key="Destination_System" value="XXX" />
</message-properties-transformer>
<file:outbound-endpoint path="${OutPathA}" connector-ref="FileConnector_1"
tracking:enable-default-events="true"/>
<!--Send email alerts -->
<all doc:name="All" >
<processor-chain>
<message-property-filter pattern="turnOffEmail=false" caseSensitive="true" doc:name="Message Property"/>
<custom-transformer class="com.XXX.YYY.ZZZ.VelocityTemplateResolver" doc:name="Java">
<spring:property name="flowName" value="PPPP"/>
</custom-transformer>
<smtp:outbound-endpoint host="${SMTP_HOSTNAME}" port="${SMTP_PORT}" user="${SMTP_USERNAME}" password="${SMTP_PASSWORD}" to="${TO_ADDRESS}" from="${FROM_ADDRESS}" subject="${MAIL_SUBJECT}" cc="${MAIL_CC_ADDRESS}" bcc="${MAIL_BCC_ADDRESS}" responseTimeout="10000" transformer-refs="emailVelocityMessageTransformer" tracking:enable-default-events="true"/>
</processor-chain>
<processor-chain>
<message-property-filter pattern="turnOffEmail=false" caseSensitive="true" doc:name="Message Property"/>
<custom-transformer class="com.XXX.YYY.ZZZ.VelocityTemplateResolver" doc:name="Java">
<spring:property name="flowName" value="FlowName"/>
</custom-transformer>
<smtp:outbound-endpoint host="${SMTP_HOSTNAME}" port="${SMTP_PORT}" user="${SMTP_USERNAME}" password="${SMTP_PASSWORD}" to="${MAIL_TO_ADDRESS}" from="${MAIL_FROM_ADDRESS}" subject="${MAIL_SUBJECT}" cc="${MAIL_CC_ADDRESS}" bcc="${BCC_ADDRESS}" responseTimeout="10000" transformer-refs="emailVelocityMessageTransformer" tracking:enable-default-events="true"/>
</processor-chain>
<processor-chain>
<message-property-filter pattern="turnOffEmail=false" caseSensitive="true" doc:name="Message Property"/>
<custom-transformer class="com.XXX.YYY.ZZZ.VelocityTemplateResolver" doc:name="Java">
<spring:property name="flowName" value="AAAA"/>
</custom-transformer>
<smtp:outbound-endpoint host="${SMTP_HOSTNAME}" port="${SMTP_PORT}" user="${SMTP_USERNAME}" password="${SMTP_PASSWORD}" to="${MAIL_TO_ADDRESS}" from="${MAIL_FROM_ADDRESS}" subject="${MAIL_SUBJECT}" cc="${MAIL_CC_ADDRESS}" bcc="${MAIL_BCC_ADDRESS}" responseTimeout="10000" transformer-refs="emailVelocityMessageTransformer" tracking:enable-default-events="true"/>
</processor-chain>
</all>
<rollback-exception-strategy doc:name="Rollback Exception Strategy" maxRedeliveryAttempts="${MAX_REDELIVERY_ATTEMPTS}" enableNotifications="false">
<logger message="==Rollback log ===" level="INFO" doc:name="Logger"/>
</rollback-exception-strategy>
</flow>
The most likely cause of the the problem is correlation ID.
You might want to inspect the correlation ID of the messages sent out to Path A and Path B. The message received on FinalResponse VM inbound endpoint needs to have the same correlation ID, otherwise it won't be accepted as a response to the messages previously sent. In other words the request-reply will NOT accept just anything in the inbound-endpoint but just the message matching the correlation ID of the posted on outbound-endpoint with the request-reply router.
You can set the custom correlation ID using this --
<set-property propertyName="MULE_CORRELATION_ID" value="some-correlation-id" />
Related
I've a mule flow where I configured Request Reply scope. The flow is like below:
<flow name="RequestReplyFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/test" doc:name="HTTP" />
<set-payload value="#['Sample Payload']" doc:name="Set Payload" />
<request-reply doc:name="Request-Reply">
<vm:outbound-endpoint exchange-pattern="one-way" path="request" doc:name="VM" />
<vm:inbound-endpoint exchange-pattern="one-way" path="reply" doc:name="VM" />
</request-reply>
</flow>
and
<flow name="RequestReplyFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="request" doc:name="VM" />
<logger message="Executing with payload: #[payload]" level="INFO" doc:name="Logger" />
<component class="org.ram.BusinessComponent" doc:name="Java" />
<rollback-exception-strategy maxRedeliveryAttempts="5" doc:name="Rollback Exception Strategy">
<logger message="Will attempt redelivery" level="INFO" doc:name="Logger" />
</rollback-exception-strategy>
</flow>
I configure rollback-exception-strategy on the request VM inbound endpoint.
When the component org.ram.BusinessComponent throws an exception, what I expected is the message is redelivered to the inbound VM endpoint but it did not happen. Why?
Can anyone please solve the issue?
If you are using rollback exception strategy instead of default exception strategy for unhandled exceptions, then you just have to specify the redirection manually in the "rollback-exception-strategy" by adding the "vm:outbound-endpoint" with the "reply" path, note that the maxRedeliveryAttempts was changed to "0" because your vm is not transactional:
<flow name="RequestReplyFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="request" doc:name="VM" />
<logger message="Executing with payload: #[payload]" level="INFO" doc:name="Logger" />
<component class="org.ram.BusinessComponent" doc:name="Java" />
<rollback-exception-strategy maxRedeliveryAttempts="0" doc:name="Rollback Exception Strategy">
<logger message="Will attempt redelivery" level="INFO" doc:name="Logger" />
<vm:outbound-endpoint exchange-pattern="one-way" path="reply" doc:name="VM" />
</rollback-exception-strategy>
</flow>
When the vm is transactional then the value maxRedeliveryAttempts=5 makes sense because in that case Mule attempts message redelivery five (5) times. Then you can specify the redirection manually in the "rollback-exception-strategy" by adding the "vm:outbound-endpoint" with the "reply" path inside the "on-redelivery-attempts-exceeded" child element:
<flow name="RequestReplyFlow1">
<vm:inbound-endpoint exchange-pattern="one-way" path="request" doc:name="VM" />
<logger message="Executing with payload: #[payload]" level="INFO" doc:name="Logger" />
<component class="org.ram.BusinessComponent" doc:name="Java" />
<rollback-exception-strategy maxRedeliveryAttempts="0" doc:name="Rollback Exception Strategy">
<logger message="Will attempt redelivery" level="INFO" doc:name="Logger" />
<on-redelivery-attempts-exceeded>
<logger message="redelivery attempt exceeded" level="INFO" doc:name="Logger" />
<vm:outbound-endpoint exchange-pattern="one-way" path="reply" doc:name="VM" />
</on-redelivery-attempts-exceeded>
</rollback-exception-strategy>
</flow>
I am having the following problem concerning asynchronous (or one-way) vm inbound endpoints. In the tests below, it seems that the number of one-way inbound endpoints is limited to 20 per vmconnector. My question is: Is there a setting on the vmconnector or a way programmatically to configure the vmconnector to remove this limitation?
I am using Mule 3.3.1 CE.
Thanks.
test1 (will fail to reach secondFlow unless the 21nd endpoint uses vmConn2):
<mule ..>
<stdio:connector name="stdioConn" messageDelayTime="1000" promptMessage="prompt >"/>
<vm:connector name="vmConn"/>
<vm:connector name="vmConn2"/>
<flow name="FirstFlow">
<stdio:inbound-endpoint system="IN" connector-ref="stdioConn"/>
<vm:outbound-endpoint exchange-pattern="one-way" path="path21" connector-ref="vmConn"/>
</flow>
<flow name="SecondFlow">
<composite-source doc:name="Composite Source">
<vm:inbound-endpoint exchange-pattern="one-way" path="path1" connector-ref="vmConn"/>
<vm:inbound-endpoint exchange-pattern="one-way" path="path2" connector-ref="vmConn"/>
<vm:inbound-endpoint exchange-pattern="one-way" path="path3" connector-ref="vmConn"/>
....
<vm:inbound-endpoint exchange-pattern="one-way" path="path20" connector-ref="vmConn"/>
<vm:inbound-endpoint exchange-pattern="one-way" path="path21" connector-ref="vmConn"/>
</composite-source>
<logger message="MESSAGE RECEIVED!" level="INFO" doc:name="Logger"/>
</flow>
test2 (same test with 21 flows):
<flow name="Flow1" >
<stdio:inbound-endpoint system="IN" connector-ref="stdioConn"/>
<vm:outbound-endpoint exchange-pattern="one-way" path="path21" connector-ref="vmConn" />
</flow>
<flow name="Flow2">
<vm:inbound-endpoint exchange-pattern="one-way" path="path1" connector-ref="vmConn" doc:name="VM" />
<logger message="MESSAGE RECEIVED!" level="INFO" doc:name="Logger" />
</flow>
<flow name="Flow3">
<vm:inbound-endpoint exchange-pattern="one-way" path="path2" connector-ref="vmConn" doc:name="VM" />
<logger message="MESSAGE RECEIVED!" level="INFO" doc:name="Logger" />
</flow>
...
<flow name="Flow21">
<vm:inbound-endpoint exchange-pattern="one-way" path="path20" connector-ref="vmConn" doc:name="VM" />
<logger message="MESSAGE RECEIVED!" level="INFO" doc:name="Logger" />
</flow>
<flow name="Flow22">
<vm:inbound-endpoint exchange-pattern="one-way" path="path21" connector-ref="vmConn" doc:name="VM" />
<logger message="MESSAGE RECEIVED!" level="INFO" doc:name="Logger" />
</flow>
Any vm connector has a thread pool of message receivers. Once the receiver are exhausted new vm inbound endpoint want be able to process messages.
To address it you should increase the number of message receivers configuring threading profiles properly
I guess that the problem may be the 'MULE_CORRELATION_ID'. I use the tag to deal a batch of datas. the configuration as follows:
<jdbc-ee:connector name="jdbcConnector" dataSource-ref="dataSource" pollingFrequency="2000" queryTimeout="-1" transactionPerMessage="false" resultSetHandler-ref="resutSetHandler" doc:name="Database">
<jdbc-ee:query key="read" value="SELECT 1 as CID, A.* from ewell_login_user A"></jdbc-ee:query>
</jdbc-ee:connector>
<file:connector name="output" outputAppend="true" outputPattern="#[function:datestamp].txt" doc:name="File"></file:connector>
<flow name="zhicall-zhongshan" doc:name="zhicall-zhongshan">
<jdbc-ee:inbound-endpoint queryKey="read" connector-ref="jdbcConnector" doc:name="Database">
</jdbc-ee:inbound-endpoint>
<message-properties-transformer doc:name="Message Properties" >
<add-message-property key="MULE_CORRELATION_GROUP_SIZE" value="10"/>
<add-message-property key="MULE_CORRELATION_ID" value="10000"/>
</message-properties-transformer>
<collection-aggregator timeout="5000" failOnTimeout="false" doc:name="Collection Aggregator"/>
<custom-transformer encoding="UTF-8" class="com.zhicall.esb.transformer.TestTransFormer" doc:name="Java"/>
<stdio:outbound-endpoint doc:name="STDIO" responseTimeout="10000" system="OUT" encoding="UTF-8"/>
</flow>
MULE_CORRELATION_ID must be unique for each group of messages.
You shouldn't be setting it and if you do, you need to make sure that you use a different id for each group.
I have a back end service that I need to throttle access to. I'm trying to use the approach described here: http://blogs.mulesoft.org/synchronous-and-asynchronous-throttling-2/
I started with a simple pass through flow that receives a SOAP request and forwards it. When I hit this using the SOAPUI utility, I get the expected response in a second or two.
<http:connector name="httpConnector" doc:name="HTTP\HTTPS">
<receiver-threading-profile maxThreadsActive="1" maxBufferSize="100" />
</http:connector>
<jms:activemq-connector name="amqConnector" brokerURL="tcp://localhost:61616" specification="1.1" doc:name="AMQ" />
<flow name="Flow1" processingStrategy="synchronous" doc:name="Flow1">
<http:inbound-endpoint exchange-pattern="request-response"
host="localhost" port="8088" path="test" doc:name="HTTP"
mimeType="text/xml" encoding="UTF-8" connector-ref="httpConnector"/>
<http:outbound-endpoint
address="http://dnbdirect-api.dnb.com/DnBAPI-11"
exchange-pattern="request-response" doc:name="HTTP" mimeType="text/xml"/>
</flow>
If I then move the outbound call to a separate flow and add in the request-reply block, the behavior changes. I get no response back (nor do I get the "After queue" message from the logger) and SOAPUI eventually times out.
<http:connector name="httpConnector" doc:name="HTTP\HTTPS">
<receiver-threading-profile maxThreadsActive="1" maxBufferSize="100" />
</http:connector>
<jms:activemq-connector name="amqConnector" brokerURL="tcp://localhost:61616" specification="1.1" doc:name="AMQ" />
<flow name="Flow1" processingStrategy="synchronous" doc:name="Flow1">
<http:inbound-endpoint exchange-pattern="request-response"
host="localhost" port="8088" path="test" doc:name="HTTP"
mimeType="text/xml" encoding="UTF-8" connector-ref="httpConnector"/>
<message-properties-transformer doc:name="Message Properties">
<add-message-property key="AMQ_SCHEDULED_DELAY" value="5000"/>
</message-properties-transformer>
<logger message="Before queue" level="INFO"/>
<request-reply>
<jms:outbound-endpoint queue="request" connector-ref="amqConnector"></jms:outbound-endpoint>
<jms:inbound-endpoint queue="response" connector-ref="amqConnector"></jms:inbound-endpoint>
</request-reply>
<logger message="After queue" level="INFO"/>
</flow>
<flow name="flow2" doc:name="Flow2">
<jms:inbound-endpoint queue="request" connector-ref="amqConnector" doc:name="JMS"/>
<http:outbound-endpoint
address="http://dnbdirect-api.dnb.com/DnBAPI-11"
exchange-pattern="request-response" doc:name="HTTP" mimeType="text/xml" />
</flow>
The throttling behavior works as I see the delays if I pull out the call to the back end service. But I can't get it to work with the service call there.
What am I missing?
I found that the message's payload will be "ArrayList" after "request-reply".
so i add a java component to split it, then the result will be corrected.
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
MuleMessage message = eventContext.getMessage();
//int groupSize = message.getCorrelationGroupSize();
//System.out.println("############# correlationGroupSize: " + groupSize);
Object payload = message.getPayload();
if (payload != null && payload instanceof ArrayList) {
//message.setPayload(((ArrayList)payload).get(0));
return ((ArrayList)payload).get(0);
}
return message.getPayload();
}
the completed flow is:
<message-properties-transformer doc:name="Message Properties">
<add-message-property key="AMQ_SCHEDULED_DELAY" value="10000"/>
</message-properties-transformer>
<request-reply storePrefix="mainFlow">
<jms:outbound-endpoint queue="request" connector-ref="amqConnector" doc:name="JMS"></jms:outbound-endpoint>
<jms:inbound-endpoint queue="response" connector-ref="amqConnector" doc:name="JMS"></jms:inbound-endpoint>
</request-reply>
<component class="com.neusoft.fx.JmsMessageTransformer" doc:name="Java"/>
<message-properties-transformer doc:name="Set Content Type">
<delete-message-property key="Content-type" />
<add-message-property key="Content-Type" value="text/xml"/>
</message-properties-transformer>
<logger message="----- LOGGER ----- after #[groovy:message.toString()]" level="INFO" doc:name="Logger" />
</flow>
Try adding the following before the HTTP outbound endpoint in flow2:
<copy-properties propertyName="MULE_*"/>
Requirement is to develop mule flow which calls 3 different sync services in parallel and then aggregate the response of each of these and send it back to caller.
I have followed fork join approach as mentioned in docs and How to make parallel outbound calls.
My config file looks like below :
<flow name="fork">
<http:inbound-endpoint host="localhost" port="8090" path="mainPath" exchange-pattern="request-response">
<set-property propertyName="MULE_CORRELATION_GROUP_SIZE"
value="2" />
<all enableCorrelation="IF_NOT_SET">
<async>
<set-property propertyName="MULE_CORRELATION_SEQUENCE"
value="1" />
<flow-ref name="parallel1" />
</async>
<async>
<set-property propertyName="MULE_CORRELATION_SEQUENCE"
value="2" />
<flow-ref name="parallel2" />
</async>
</all>
</flow>
<sub-flow name="parallel1">
<logger level="INFO" message="parallel1: processing started" />
<!- Transformation payload -->
<http:outbound-endpoint address="..."
exchange-pattern="request-response" />
<logger level="INFO" message="parallel1: processing finished" />
<flow-ref name="join" />
</sub-flow>
<sub-flow name="parallel2">
<logger level="INFO" message="parallel2: processing started" />
<!- Transformation payload -->
<http:outbound-endpoint address="..."
exchange-pattern="request-response" />
<logger level="INFO" message="parallel2: processing finished" />
<flow-ref name="join" />
</sub-flow>
<sub-flow name="join">
<collection-aggregator timeout="6000"
failOnTimeout="true" />
<combine-collections-transformer />
<logger level="INFO" message="Continuing processing of: #[message.payloadAs(java.lang.String)]" />
<set-payload value="Soap XML Response"/>
</sub-flow>
I am able to verify that till "join" subflow is working fine but the response is not coming back as "Soap XML Response".
The response is the same initial SOAP Request.
How can I make this thread wait till sub-flow processing is complete and it sends back response whatever "join" sub-flow returns ??
The fork join in the above post looks good. The issue here is there is no way to capture the payload after the join and bring it back to the main flow.
As the calls to parallel made async the main flow continues without waiting for the join output.
I have modified the flow to address this issue. Now the flow will have a processor to wait for the reply and read the joined output to be written onto the http transformer.
<flow name="fork">
<http:inbound-endpoint host="localhost" port="8090" path="mainPath" exchange-pattern="request-response">
<!-- To get back the response after the fork-join -->
<request-reply timeout="60000">
<jms:outbound-endpoint queue="parallel.processor.queue">
<message-properties-transformer scope="outbound">
<delete-message-property key="MULE_REPLYTO" />
</message-properties-transformer>
</jms:outbound-endpoint>
<jms:inbound-endpoint queue="join.queue" >
</jms:inbound-endpoint>
</request-reply>
</flow>
<flow name="fork_join_flow" >
<jms:inbound-endpoint queue="parallel.processor.queue" exchange-pattern="one-way" />
<set-property propertyName="MULE_CORRELATION_GROUP_SIZE"
value="2" />
<all enableCorrelation="IF_NOT_SET">
<async>
<set-property propertyName="MULE_CORRELATION_SEQUENCE"
value="1" />
<flow-ref name="parallel1" />
</async>
<async>
<set-property propertyName="MULE_CORRELATION_SEQUENCE"
value="2" />
<flow-ref name="parallel2" />
</async>
</all>
</flow>
<sub-flow name="parallel1">
<logger level="INFO" message="parallel1: processing started" />
<!- Transformation payload -->
<http:outbound-endpoint address="..."
exchange-pattern="request-response" />
<logger level="INFO" message="parallel1: processing finished" />
<flow-ref name="join" />
</sub-flow>
<sub-flow name="parallel2">
<logger level="INFO" message="parallel2: processing started" />
<!- Transformation payload -->
<http:outbound-endpoint address="..."
exchange-pattern="request-response" />
<logger level="INFO" message="parallel2: processing finished" />
<flow-ref name="join" />
</sub-flow>
<sub-flow name="join">
<collection-aggregator timeout="6000"
failOnTimeout="true" />
<combine-collections-transformer />
<logger level="INFO" message="Continuing processing of: #[message.payloadAs(java.lang.String)]" />
<set-payload value="Soap XML Response"/>
<jms:outbound-endpoint queue="join.queue">
</jms:outbound-endpoint>
</sub-flow>
Hope this helps.