Wednesday, June 7, 2017

MuleSoft Programatically Invoking Flows

1.0 Overview

MuleSoft documentation talks about types of flows and how they behave during runtime (synchronous or asynchronous), but it doesn’t talk about the method in which a developer could programmatically invoke a flow. This article will attempt to bring clarity to this area.
You can programmatically invoke a flow via two methods, you can do it by transport or by flow reference (figure 1.0 below).

Figure 1.0
I have previously written an article about the relationship between flow scopes and mule’s variable types, but that article is based on the premise of invoking flow through transports. I will not repeat myself here but instead talk about the contrast between invoking flow by transport versus invoking flow by reference.

I can only demonstrate this contrast via actual code, the next few sessions would be a walk through about the code I have created to illustrate this contrast.

2.0 The Code That Illuminates the Concept

At a glance the complete code that shows the internal intricate differences between invoking an external flow either by transport or by reference is as illustrated in Figure 2.0.

Figure 2.0
This mule app has only 3 flows, the shortest flow (the one right at the bottom of Figure 2.0) is the simulated external flow. The two other flow above the “ExternalFlow” exists to demonstrate the internal runtime difference between the invocation methods. Both “InvocationByTransport” and “InvocationByFlowRef” have all the same message processors, the only difference between the two is how it passes execution control to the “External” flow.

During runtime “InvocationByTransport” flow passes execution control to “ExternalFLow” via transport invocation (meaning it is trying to invoke ExternalFlow by HTTP transport, but “InvocationByFlowRef” flow passes execution control to “ExternalFlow” by flow references, which means it does not go through HTTP transport, in short it by passes “ExternalFlows” in bound HTTP Receive endpoint and go straight in to “ExternalFlow”’s message processors.

The sub-flow at the very top of Figure 2.0 is the groovy script that prints out all the HTTP parameters, flow variables and session variables. The code for the groovy script are as per listed in the following code block.

println "---------------------------------------------------------------------------"
println "List of inbound properties ..."
message.getInboundProperty('http.query.params').each{k,v -> println "${k}:${v}" }
println " "

println "List of outbound properties ..."
message.getOutboundProperty('http.query.params').each{k,v -> println "${k}:${v}" }
println " "

println "flowVars :"
println flowVars.randomFlowVariable
println " "

println "sessionVars :"
println sessionVars.randomSessionVariable
println " "

println "Payload ..."
println message.payload
println "---------------------------------------------------------------------------"
println " "

return message.payload

It is very important to key in the “return message.payload” statement at the end of the groovy script else you will lose your initial payload. You can get the full source code from the following link.

3.0 The Test That Will Show You the Truth

If you have downloaded the code in section 2.0, we could now test it together and analyse the behaviour of both flow invocation methods.

I will use postman for testing the flows for the mentioned mule application in Figure 2.0. (link to youtube tutorial of postman).

I am using the same set of parameters and payload to test both “InvocationByTransport” and “InvocationByFlowRef” flows, listed below would show how the URL looks like for testing each flow respectively.


Figure 3.0 shows what postman would look like when testing both different invocation methods.



We will test the flows respectively with a POST request and with the payload of “Test Payload”, the query parameters that you will key in will remain the same for both flow URLs.

We want to post request for the two different invocation methods so that we could collate the console logs and look at the contrasting difference.

The Anypoint Studio console logs will show us what really is happening behind the scenes.

3.1 Analysing the Test Results

If you use postman to execute a post request to the respective URLs you will get the two respective logs as described by the following table. The right most column shows the execution log for "InvocationByFlowRef" and the second right most column shows the execution result for "InvocationByTransport" mule flow.

The following table illustraited the log content that has been churned out via our testing activities. This table is segregated into 3 segments the first segment (1) shows the log messages spit out by the main flow, the second segment (2) shows the log message spit out by the "ExternalFlow" when execution control is relayed to it via the main flow. Finally the last segment (3) shows the logs messages that is generated by the main flow when execution control is retuned back to it from the "ExternalFlow".

Execution Control
Invocation by transport
Invocation by Flow Reference
(1) Main Flow
INFO  2017-06-07 21:42:35,497 [[flowrefvstransportinvocation].HTTP_8081.worker.01] org.mule.api.processor.LoggerMessageProcessor: (Invocation By Transport) Before Invocaiton : ---------------------------------------------------------------------------
---------------------------------------------------------------------------
List of inbound properties ...
lastname:ting
firstname:kian
topic:invocationbyTransportVSbyFlowRef

List of outbound properties ...
lastname:ting
firstname:kian
topic:invocationbyTransportVSbyFlowRef

flowVars :
randomFlowVariable

sessionVars :
randomSessionVariable

Payload ...
 Test Payload
-------------------------------------------------------


INFO  2017-06-07 21:43:56,901 [[flowrefvstransportinvocation].HTTP_8082.worker.01] org.mule.api.processor.LoggerMessageProcessor: (Invocation By FlowRef) Before Invocaiton  : ---------------------------------------------------------------------------
---------------------------------------------------------------------------
List of inbound properties ...
lastname:ting
firstname:kian
topic:invocationbyTransportVSbyFlowRef

List of outbound properties ...
lastname:ting
firstname:kian
topic:invocationbyTransportVSbyFlowRef

flowVars :
randomFlowVariable

sessionVars :
randomSessionVariable

Payload ...
 Test Payload
-------------------------------------------------------


(2) External Flow
INFO  2017-06-07 21:42:35,934 [[flowrefvstransportinvocation].HTTP_8083.worker.01] org.mule.api.processor.LoggerMessageProcessor: (External Flow)  Initial Invocation Settings  : --------------------------------------------------------------------------

List of inbound properties ...

List of outbound properties ...

flowVars :
null

sessionVars :
null

Payload ...
 Test Payload
-------------------------------------------------------
INFO  2017-06-07 21:43:56,915 [[flowrefvstransportinvocation].HTTP_8082.worker.01] org.mule.api.processor.LoggerMessageProcessor: (External Flow)  Initial Invocation Settings  : --------------------------------------------------------------------------
List of inbound properties ...
lastname:ting
firstname:kian
topic:invocationbyTransportVSbyFlowRef

List of outbound properties ...
lastname:ting
firstname:kian
topic:invocationbyTransportVSbyFlowRef

flowVars :
randomFlowVariable

sessionVars :
randomSessionVariable

Payload ...
 Test Payload
-------------------------------------------------------
(3) Back In Main Flow
INFO  2017-06-07 21:42:35,989 [[flowrefvstransportinvocation].HTTP_8081.worker.01] org.mule.api.processor.LoggerMessageProcessor: (Invocation By Transport) After Invocaiton  : ---------------------------------------------------------------------------
---------------------------------------------------------------------------
List of inbound properties ...

List of outbound properties ...

flowVars :
randomFlowVariable

sessionVars :
randomSessionVariable

Payload ...
 Test Payload + "appended string from ExternalFlow ..."
-------------------------------------------------------
INFO  2017-06-07 21:43:56,918 [[flowrefvstransportinvocation].HTTP_8082.worker.01] org.mule.api.processor.LoggerMessageProcessor: (Invocation By FlowRef) After Invocaiton  : ---------------------------------------------------------------------------
---------------------------------------------------------------------------
List of inbound properties ...
lastname:ting
firstname:kian
topic:invocationbyTransportVSbyFlowRef

List of outbound properties ...
lastname:ting
firstname:kian
topic:invocationbyTransportVSbyFlowRef

flowVars :
randomFlowVariable

sessionVars :
randomSessionVariable

Payload ...
 Test Payload + "appended string from ExternalFlow ..."
---------------------------------------------------------------------------

Both "InvocationByTransport" (second left column) and "InvocationByFlowRef" (left most column) starts out the same in segment (1), both of them have the same set of flow variable, session variable, inbound and outbound properties, both even have the same payload.

Segment (2) of the log is where things start to look interesting, "InvocationByTransport" flow relays execution control to “ExternalFlow” via HTTP transport which differs to “InvocationByFlowRef” which relays control to “ExternalFlow” by way of “Flow Reference”. Relaying execution control by way of transport will only have the test payload preserved, which mean in other word “ExternalFlow” can only access the paylod of “InvocationByTransport”. If execution control is relayed by “Flow Reference”, everything is preserved, and the external flow could still access the flow variables, session variables, inbound and outbound properties of “InvocationByFlowRef”.

The last segment (3) of the console log shows variable and property values that are still accessible by the main calling flow. If execution is relayed back from “ExternalFlow” via HTTP response transport (second left column) you will see that all inbound and outbound properties are lost, only the initially created flow and session variables are still accessible. Contrary to the relaying back control from “Flow Reference” (left most column), we are able to see that everything is preserved, the initial inbound and outbound properties of the main flow is still accessible and so are the flow and session variables.

4.0 Conclusion

It is always good to have a conclusion pertaining to an experiment, the following table summarizes my conclusion pertaining to flow execution by transport or by flow reference.
Execution Scope
Execution by Transport
Execution by “Flow Reference”
When Execution Control is passed to Target External Flow
Property Type
Is Accessible
Flow Variables
N
Session Variables
N
Inbound Properties
N
Outbound Properties
N
Payload
Y
Property Type
Is Accessible
Flow Variables
Y
Session Variables
Y
Inbound Properties
Y
Outbound Properties
Y
Payload
Y
When Execution Control is passed back to calling flow
Property Type
Is Accessible
Flow Variables
Y
Session Variables
Y
Inbound Properties
N
Outbound Properties
N
Payload
Y
Property Type
Is Accessible
Flow Variables
Y
Session Variables
Y
Inbound Properties
Y
Outbound Properties
Y
Payload
Y
From the table we could conclude the behaviour of invocation by “Flow Reference” is analogous to treating the target external flow as part of the main flow, and whatever property or variables is created in the main flow is still accessible via the invoked external flow.

2 comments: