Logic Apps: How to add several actions inside a Loop (or foreach actions)

Posted: April 21, 2016 in Azure App Services, Logic Apps
Tags: , , , , , , , ,

Following my latest posts where I talked about the new “The ability to call nested Logic Apps directly from Logic Apps Designer”. 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;

Using/Implementing Looping inside Logic Apps

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.

01-Logic-Apps-Conditions-shape

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.

The current design doesn’t have any more this option, but again that doesn’t mean that you can’t. In this new Logic App version or designer, if it detects that the input from the previous action or trigger it’s an array, and if you try to use this input in a subsequent action, it will, almost every time, automatically put you on a for each operation. Which means that you are running this action for each item in that list.

Let’s look, and use, the basic scenario that we are using in the last posts, were:

  • The Logic Apps is trigger by a new tweet containing the hashtag we are listening;
  • And then create a file;

For now, let’s ignore the dynamic creation of the file name using Azure Functions. So we have this basic Logic App

02-Logic-Apps-Looping-no-loop-Basic-flow

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.

03-Logic-Apps-Looping-no-loop-Basic-flow-code-view

So let’s make some changes!

We will use a similar scenario, but this time we want that our Logic App:

  • To be triggered every hour;
  • Retrieve the last 20 tweets with the hashtag #LogicApp
  • And then create a file for each tweet in our Dropbox

For that we will create a new Logic App called “LoopingInsideLogicApps

  • Add a “Recurrence” trigger, and set the:
    • Frequency” property to “Hour
    • And the “Interval” property to “1

04-Logic-Apps-Looping-Reccurence-Trigger

  • Select the plus sign, and then choose “Add an action
  • From the search box select “Show Microsoft managed APIs”, type “twitter” and select the “Twitter – Search tweet” action
    • Set the “Query text” property with “#LogicApps” hashtag
    • You can expand the action to see all the properties if you click “” in the lower left corner
    • And see and define the number of result you want to return

05-Logic-Apps-Looping-Search-For-Tweets

  • Select the plus sign, and then choose “Add an action
  • From the search box select “Show Microsoft managed APIs”, type “Dropbox” and select the “Dropbox – Create file” action
    • Set the “Folder path” property, let’s say the root by typing: /
    • On the “File name” property, set the parameter “Tweet id” from the output of “Search tweet” action as input, following by the string “.txt”
    • On the “File Content” property, set the parameter “Tweet text” from the output of “Search tweet” action as input

06-Logic-Apps-Looping-For-each-Tweets-Create-File

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.

07-Logic-Apps-Looping-For-each-Tweets-Create-File-dropbox

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.

Trying to add several actions inside a for each

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.

At first glance, we might say that:

  • After the “Twitter – Search tweet” action, we need to call our Azure Function: “CreateFileName”, because it doesn’t need inputs we set the input as an empty JSON message
  • And reconfigure the “Dropbox – Create file” action in order that the “File name” property is set with the “Filename” parameter from the output of “CreateFileName” function as input

08-Logic-Apps-Looping-For-each-Tweets-several-actions

If we once again, “Save” our Logic Apps and this time, execute it manually to for it to run. You will notice that:

  • The CreateFileName function is successfully executed;
  • But the Create file action failed. If you see the output, you will notice that the first file was created successfully but the following one’s got the following error:

File ‘/NewTweet_6785b86d-4dda-4119-968f-c189416f22bc.txt’ already exists. Use the Update operation to update an existing file.

09-Logic-Apps-Looping-For-each-Tweets-several-actions-create-dropbox-files-error

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": "no-cache",    
        "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

10-Logic-Apps-Looping-For-each-Tweets-several-actions-create-dropbox-files-error-why

Trying to add several actions inside a for each (second shoot)

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?

Let’s them make some changes to our Logic App flow:

  • First, delete the “File Name” property from the “Dropbox – Create file” action
    • Leave it empty
  • Second, let’s send a dummy JSON message to our Azure Function, forcing this action to iterate over the “Search tweet” output array of items by setting the following JSON message:
   
{ "dummy": ['Tweet text'] }    

11-Logic-Apps-Looping-CreateFileName-Dummy-Msg

If we switch to “Code view” you will notice that now this action is under a for each:

   
"foreach": "@body('Search_tweet')"    

12-Logic-Apps-Looping-CreateFileName-Dummy-Msg-code

The problem of this approach is that

  • CreateFileName” action
  • And “Dropbox – Create file” action

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:

13-Logic-Apps-Looping-CreateFileName-Design-error

Basic workaround to solve this problem

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:

  • the twitter message

and return two parameters:

  • The filename generated
  • And the twitter message that was passed as an input

For example:

   
module.exports = function (context, data) {    
        
  var Tweet = data.Tweet;    
  var d = new Date().getTime();    
  var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {    
        var 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": ['Tweet text'] }    

14-Logic-Apps-Looping-CreateFileName-with-input-Msg

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

15-Logic-Apps-Looping-Dropbox-with-CreateFileName-values

This will tell to this action to iterate over the function output array to create all the files in Dropbox.

16-Logic-Apps-Looping-Dropbox-with-CreateFileName-values-code

Once again, if we “Save” our Logic App and run it, we will see that now everything will work fine.

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?

How to add several actions inside a for each

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).

Still remember our Logic App that we create in my previous posts called “AddFileToDropbox” that:

  • Its trigger manually, which means through a HTTP post, allowing to be invoked by other Logic Apps
  • Then it will call an Azure Function to dynamically generate a filename;
  • Create a Dropbox file
  • The filename it’s provide by the Azure Function;
  • And the content of the message it’s passed in the HTTP request that triggers this Logic App.
  • And finally return an HTTP response based on the status of the file creation

We will reuse this “child” Logic App in this demo now.

So what we need to do now is delete the last two action from our current Logic App:

  • “Dropbox – Create file” action
  • And call “CreateFileName” function action

And then call our “child” Logic App “AddFileToDropbox”. To accomplish that we need:

  • Select the plus sign, and then choose “Add an action
  • When you select “Add an Action”, the search box will be presented were all the available actions. But now, on the search box you can select the option: “Show Logic Apps in the same region
    • And then select “AddFileToDropbox
    • On the “Text” property we need to set the parameter “Tweet text” from the output of “Search tweet” action as input

17-Logic-Apps-Looping-Call-Logic-app-to-add-multiple-actions

If we now “Save” our Logic App and run it manually, we instantly see that:

  • the “Search tweet” action was successfully executed
  • and the “AddFileToDropbox” action is being executed

18-Logic-Apps-Looping-Call-Logic-app-to-add-multiple-actions-executions

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

19-Logic-Apps-Looping-Call-Logic-app-to-add-multiple-actions-executions-child

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)

How is the behavior of calling a nested Logic App inside a foreach statement?

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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s