I was recently tasked with developing a set of Logic Apps for an internal hackathon project. When setting a variable value inside a For-Each loop, I had an unexpected behavior where the same value would be used repeatedly. Here's how to get around it!
We will use a simple example to understand the issue and a possible workaround.
The Sample App
In our example, the Logic App will receive an array of email addresses from an HTTP trigger and send an email to each of those email addresses. The body of the email will be our emailBody variable and will contain the receiver's email as part of the text.
Here's our initial setup:
Logic App used in this post
We are first initializing the emailBody variable, as you cannot do this inside the loop. Note that this is a hint that the variable's scope is outside of the For-Loop.
Then, inside the For-Each loop, we set the emailBody variable to the following expression:
concat('Hi there ', items('For_each'), ', welcome to the example!')
This expression concatenates the body of our email with the recipient's email as part of the text (or so we hope!).
It then sends an email using the Outlook 365 Send an email (V2) block. We use the Current item of the loop as the To, and our emailBody variable as the Body parameter.
The expected result would be that an email gets sent to each of the emails received in the trigger, with a customized message containing the user's email. However, this is not what happens. Due to the parallelism incurred in the For-Each loop, when we run this example, this is the result of both the emails we sent as the trigger body:
User 1 got the right email
User 2 got the wrong email
As you can see, although the value in To, coming from the Current items variable, was set correctly in both instances, the Body contained the same value (email@example.com) in both runs. Both executions in our example used the same dirty value for the emailBody variable (keep reading for explanations).
To get around this, we are going to use the Compose action instead of setting a variable, like this:
Replacing variable setting with compose
We are using the same concat expression we used to set the variable value in the previous version. We then set the Body of the Send an email (V2) block to the Outputs of the Compose action. The result can be seen below:
User 1 gets the right email
User 2 gets the right email
As you can see, the email has now been sent correctly, as expected!
As to why this behavior happens, it's primarily due to the 'dirty reads' in the For-Each loop. Because we are running the variable assignment in parallel, we cannot ensure that the variable is being set and read correctly in each run.
Another workaround would have been to decrease the parallelism level to 1 in the For-Each block's settings. Reducing concurrency would force the For-Each loop to execute one block at a time, thus avoiding the problem.
Setting For-Each concurrency
However, reducing concurrency means that your loop would take a lot more time to run, so using the Compose action discussed above seems better.
We hope this article was an interesting read and helped you achieve your desired result. Let us know if you faced a situation where reducing concurrency was the only way out!