Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Threads and Private Flows in Mule

DZone's Guide to

Threads and Private Flows in Mule

· Java Zone
Free Resource

Learn how our document data model can map directly to how you program your app, and native database features like secondary indexes, geospatial and text search give you full access to your data. Brought to you in partnership with MongoDB.

One of the things that I believe is slightly complicated in Mule is the behaviour of private flows.Wait… is there a difference between private flows and sub-flows?

Well there is, and if you are not aware of it, it might bite you very badly. Let’s start from the easiest behaviour; sub-flows.

Flow-ref to sub-flow behaves just like method calls. It is always performed in synchronous mode, which means the caller waits for the sub-flow to finish, and then it’s executed by the same thread. The payload returned by the sub-flow will replace that of the original caller on return. This behaviour is always consistent, irrelevant of any other settings.

Private flows behave in the same way ONLY if at least one of the following conditions are met:

  • The calling flow is synchronous
  • The private flow’s processing strategy is explicitly set to synchronous

If the above conditions are not met, the flow-ref to the private flow behaves the same way as if the flow-ref was placed in an async block. Hence, the caller does not wait for the private flow to finish, and the result of the private flow does not affect the payload of the calling flow. Furthermore, the private flow is executed in its own separate thread.

Here are a few examples to illustrate this behaviour. Mule 3.5.0 was used for these tests. We start with a main flow having an HTTP request-response inbound endpoint, which forces synchronous behaviour. This flow makes two calls using flow-ref; to a sub-flow and to a private flow.

 <flow name="mainFlow" doc:name="mainFlow">
        <http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" doc:name="HTTP"/>
        <set-payload value="main flow" doc:name="Set Payload"/>
        <logger message="MAIN FLOW -- Started flow - { payload = #[message.payload] }" level="INFO" doc:name="Logger"/>
        <flow-ref name="subFlow" doc:name="Calling Sub Flow"/>
        <logger message="MAIN FLOW -- Called sub flow - { payload = #[message.payload] }" level="INFO" doc:name="Logger"/>
        <flow-ref name="privateFlow" doc:name="Calling Private Flow"/>
        <logger message="MAIN FLOW -- Called private flow - { payload = #[message.payload] }" level="INFO" doc:name="Logger"/>
    </flow>
    <sub-flow name="subFlow" doc:name="subFlow">
        <set-payload value="sub-flow" doc:name="Set Payload"/>
        <logger message="SUBFLOW - { payload = #[message.payload] }" level="INFO" doc:name="Logger"/>
    </sub-flow>
    <flow name="privateFlow" doc:name="privateFlow" >
    	<set-payload value="private-flow" doc:name="Set Payload"/>
        <logger message="PRIVATE FLOW - { payload = #[message.payload] }" level="INFO" doc:name="Logger"/>
    </flow>
You can see the behaviour in the following logs. All calls to the logger were executed by the same thread, and the final result of the private flow replaced the main flow’s payload.
[[test].connector.http.mule.default.receiver.02] MAIN FLOW -- Started flow - { payload = main flow }
[[test].connector.http.mule.default.receiver.02] SUBFLOW - { payload = sub-flow }
[[test].connector.http.mule.default.receiver.02] MAIN FLOW -- Called sub flow - { payload = sub-flow }
[[test].connector.http.mule.default.receiver.02] PRIVATE FLOW - { payload = private-flow }
[[test].connector.http.mule.default.receiver.02] MAIN FLOW -- Called private flow - { payload = private-flow }
If we simply change the inbound endpoint from request-response to one-way, the behaviour changes as you can see in the following log file.
[[test].mainFlow.stage1.02] MAIN FLOW -- Started flow - { payload = main flow }
[[test].mainFlow.stage1.02] SUBFLOW - { payload = sub-flow }
[[test].mainFlow.stage1.02] MAIN FLOW -- Called sub flow - { payload = sub-flow }
[[test].mainFlow.stage1.02] MAIN FLOW -- Called private flow - { payload = sub-flow }
[[test].privateFlow.stage1.02] PRIVATE FLOW - { payload = private-flow }
As shown, the private flow execution was carried out by a separate thread, and it did not affect the main flow’s payload.

If we set the processing strategy on the private flow to synchronous and leave the inbound endpoint as one-way (shown below), we get the original behaviour as seen in the following logs.

[[test].connector.http.mule.default.receiver.02] MAIN FLOW -- Started flow - { payload = main flow }
[[test].connector.http.mule.default.receiver.02] SUBFLOW - { payload = sub-flow }
[[test].connector.http.mule.default.receiver.02] MAIN FLOW -- Called sub flow - { payload = sub-flow }
[[test].connector.http.mule.default.receiver.02] PRIVATE FLOW - { payload = private-flow }
[[test].connector.http.mule.default.receiver.02] MAIN FLOW -- Called private flow - { payload = private-flow }
    <flow name="mainFlow" doc:name="mainFlow">
        <http:inbound-endpoint exchange-pattern="one-way" host="localhost" port="8081" doc:name="HTTP"/>
        <set-payload value="main flow" doc:name="Set Payload"/>
        <logger message="MAIN FLOW -- Started flow - { payload = #[message.payload] }" level="INFO" doc:name="Logger"/>
        <flow-ref name="subFlow" doc:name="Calling Sub Flow"/>
        <logger message="MAIN FLOW -- Called sub flow - { payload = #[message.payload] }" level="INFO" doc:name="Logger"/>
        <flow-ref name="privateFlow" doc:name="Calling Private Flow"/>
        <logger message="MAIN FLOW -- Called private flow - { payload = #[message.payload] }" level="INFO" doc:name="Logger"/>
    </flow>
    <sub-flow name="subFlow" doc:name="subFlow">
        <set-payload value="sub-flow" doc:name="Set Payload"/>
        <logger message="SUBFLOW - { payload = #[message.payload] }" level="INFO" doc:name="Logger"/>
    </sub-flow>
    <flow name="privateFlow" doc:name="privateFlow" processingStrategy="synchronous">
    	<set-payload value="private-flow" doc:name="Set Payload"/>
        <logger message="PRIVATE FLOW - { payload = #[message.payload] }" level="INFO" doc:name="Logger"/>
    </flow>

I hope you enjoyed this blog post.

Discover when your data grows or your application performance demands increase, MongoDB Atlas allows you to scale out your deployment with an automated sharding process that ensures zero application downtime. Brought to you in partnership with MongoDB.

Topics:

Published at DZone with permission of Alan Cassar, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}