Following my latest article where I talked about the new ability to call nested Logic Apps directly from Logic Apps Designer and how this feature will allow us to:
In this article let’s look how a nested Logic App can help us overcome the current Logic Apps limitation regarding to for each operation, in special, the ability to add more than one action inside the loop;
If you are used to work with BizTalk Server, we have certain shapes and behaviors inside BizTalk Orchestrations that we would love to have in Logic Apps, at a first glimpse, we may be surprised the lack of features/shapes to perform certain operations…however, that doesn’t mean that they are missing, most of the times we still can do those things… but in a different manner, so we may need to look the “problem” from another angle.
Looping is one of those things!
We don’t have any Looping shape, action or operation that we can use in the Logic App Designer, similar to what we have with Conditions.
In the previous designer (v1) we had an option in the connectors, “Repeat over the list“, that allowed us to iterate over an array of items and run an action for each item in that list.
For now, let’s ignore the dynamic creation of the file name using Azure Functions. So we have this basic Logic App
Because each tweet will generate a new execution of this Logic App, the trigger input will be a simple single message and not an array. If we switch to code view we will see that the Create file action will only be executed once and it’s not inside of any loop operation.
So let’s make some changes!
If we “Save” our Logic Apps we will notice that 20 new files will be created in our Dropbox without us having defined any parameter or configuration inside the actions that would tell it to iterate over a list/array.
This happened, because the designer “was smart” to understand that in input from the “Search Tweet” action is an array and automatically told the “Create file” action to work inside a for each so that it could iterate over all the items in the array.
Let’s say now that we want to call our Azure Function to generate the file name and create the file name in our Dropbox with it.
If we once again, “Save” our Logic Apps and this time, execute it manually to for it to run. You will notice that:
File ‘/NewTweet_6785b86d-4dda-4119-968f-c189416f22bc.txt’ already exists. Use the Update operation to update an existing file.
Maintaining in the run history, but selecting the “CreateFileName” action to see what was the output of the function we will notice that it was a simple output:
{
"statusCode"
: 200,
"headers"
: {
"pragma"
:
"no-cache"
,
"cache-Control"
"date"
"Wed, 20 Apr 2016 15:01:18 GMT"
"set-Cookie"
"ARRAffinity=9b8e91fd330bc5b8e4bdd3e129b0412d5daca54f6c2ff8a25f773cd80fad03aa;Path=/;Domain=functionssandromsdn.azurewebsites.net"
"server"
"Microsoft-IIS/8.0"
"x-AspNet-Version"
"4.0.30319"
"x-Powered-By"
"ASP.NET"
},
"body"
"FileName"
"NewTweet_6785b86d-4dda-4119-968f-c189416f22bc.txt"
}
If we go back to our Logic App designer and switch to “Code View” we will notice why this happened. By setting the input of our function with and empty JSON message were are not telling to the Logic App to iterate over the output array from the “Search Tweet” action and call the function to generate a different file name for each item.
Instead if we analyze the code we will see that the “CreateFileName” function is only call one time, and we will send to the connector Dropbox this same value to all the tweets
Ok, that didn’t work well. So what if we try to force the call to the Azure Function to be inside the for each statement?
"dummy"
: [
'Tweet text'
] }
If we switch to “Code view” you will notice that now this action is under a for each:
"foreach"
"@body('Search_tweet')"
The problem of this approach is that
Are in two different for each statements and if we try to use both in the same action, for example trying to set the “Body” parameter from the output “CreateFileName” function we will receive the following error:
So, one of the workaround that you have is to modify your Azure Function, or create a new one to be able to receive one parameter:
module.exports =
function
(context, data) {
var
Tweet = data.Tweet;
d =
new
Date().getTime();
uuid =
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
.replace(/[xy]/g,
(c) {
r = (d + Math.random()*16)%16 | 0;
d = Math.floor(d/16);
return
(c==
'x'
? r : (r&0x3|0x8)).toString(16);
});
// Response of the function to be used later.
context.res = {
body: {
Msg: Tweet.text,
FileName:
'TweetMsg_'
+ uuid +
".txt"
};
context.done();
If we are using this strategy, we then need to configure the input of the function as:
"Text"
This will iterate over the list of tweets and will create another list containing all the information that we need to send to the Dropbox connector.
We then need to change all the parameters of the “Dropbox – Create file” action and instead of configuring with values from the “Search tweet” action that will force it to iterate, we will bind it to the output provide by the Azure function output
This will tell to this action to iterate over the function output array to create all the files in Dropbox.
However, in this basic workaround we are not adding several actions to a for each statement, instead we are avoiding, going around it and duplicate the content in another list/array… but it’s there another way?
Indeed, there is a better way to accomplish that, and the solution is to call another Logic App (at least while we do not have this functionality in the design).
If we now "Save” our Logic App and run it manually, we instantly see that:
We can go to our “child” Logic App to see its runs (the historic) and you probably see that some of them are already finish and others are still running
Once all the child runs caused by the action of the parent are finished, the parent Logic App will receive the knowledge and will terminate successfully also (if all the runs finish successfully)
You may ask yourself how that works, it will execute on iteration one by one, in other words, in other words, will it call the child Logic App synchronously and wait for it to finish returning the response to call another one? Or it will be asynchronous?
Well in BizTalk terms it would be like using a Parallel Actions shape, were all the actions will be executed concurrently but independently but the parent Logic App processing does not continue until all have completed. The parent Logic App in this case will receive an array containing all the responses of the child executions.
This article was originally published at Logic Apps: How to add several actions inside a Loop (or foreach actions). But please feel free to improve this article by adding new missing or important content, fixing spelling and so on.
Another important place to find a huge amount of Logic Apps related articles is the TechNet Wiki itself. The best entry point is Microsoft Azure App Service Resources on the TechNet Wiki.