Azure Logic Apps is a powerful integration platform.
Some workflows naturally land themselves to recursion. For instance, handling a hierarchical data structure often has a natural recursive solution.
Azure Logic Apps doesn’t allow recursion directly. It forbids a Logic App invoking itself.
In this article we are going to explore two avenues to deal with recursion in Logic Apps:
- Using a simple indirection to work around the limitation.
- Flattening the hierarchy to run everything in one Logic App Instance.
As usual, source code is in GitHub.
Recursing with Parent-Child
The first approach consists in working around the direct recursion.
Instead of having a Logic App calling itself, we have it (the parent) call another Logic App (the child) that call it back.
Let’s look at an example:
ARM Template
The ARM template is a little tricky since we have a circular reference.
To work around that, we deploy both Logic Apps twice. First, we deploy an trivial empty version of each. We then deploy both complete versions. With the second deployment, each app exists, so they can reference each other.
We can’t deploy the same resource twice in the same ARM template. We accomplish this double deployment by using a deployment resource (Microsoft.Resources/deployments). It points to another ARM template which does the init deployment.
Testing the example
We have two logic apps:
- Let’s select the parent-app and go to its designer view
- Let’s open the trigger When a HTTP request is received
- We can copy its HTTP POST URL
The URL is obviously unique to the Logic App.
In order to test the apps, we need to do an HTTP POST. Different tool can be used, such as CURL or Postman.
The HTTP body must conform to a simple schema. Let’s use the following content:
{ "iterations": 3 }
We should obtain the following:
The response is 3, 2, 1, Done!
. This is computed using recursion to illustrate our point.
Logic Apps Implementation
Let’s look at the Parent App. This is quite straight forward:
- We first parse the payload using the simple schema
- We then check if the iterations value is greater than zero (0)
- If it is greater than zero, we call the child logic app with iterations – 1, we then return the current iteration and append “, ” and the return of the child app
- Otherwise, we return “Done!”
This is a typical recursive algorithm.
The child app is trivial: it calls the parent logic app, passing the input payload.
Monitoring
We can easily monitor. Let’s look at the parent-app:
The was 4 runs. The first received 3, then 2, then 1, then 0.
Flattening the recursion
Let’s look at how we could run everything in one Logic App.
The example we are going to take is something that receives a hierarchical payload. This is for simplicity: the hierarchy could have come from a file, a database, a service, etc. .
[ { "name": "master-1", "children": [ { "name": "child-1-A", "children": [ { "name": "child-1-A-I", "children": [ { "name": "child-1-A-I-Alpha", "children": []
The schema is available here.
Our strategy is to implement and until loop. We start with the root nodes. We use variables to accumulate the children of those nodes for the next loop.
Testing the example
Let’s deploy the example:
This deploys one Logic App: flatening-logic-app.
As for the first example, we’ll grab the URL.
We can then test the URL with a non-trivial:
We can see the output is a simple JSON where the processed property contains all the nodes of the input payload in a breadth first order.
Logic Apps Implementation
The implementation contains a few actions but is quite simple. In pseudo code it would look like this:
parse-payload = Parse(Payload) return-array = [] current-items = parse-payload next-items = [] Until(current-items is not empty) next-items = [] foreach i in current-items return-array.Append(i.name) foreach c in i.children next-items.Append(c) current-items = next-items return return-array
No magic here: we unfold a hierarchical data structure in a loop.
Notice that we added “debug” actions where we capture the value of a variable for later troubleshooting.
Monitoring
Now if we look at the monitoring, we obviously have only one run per invocation:
Variation
This example doesn’t cover all the recursion cases. It is a typical example, but different scenarios would call for different solutions.
Pros & Cons
If we contrast both approaches we could do a pros & cons.
For the parent-child approach:
- Pros:
- Essentially keep the recursion intact
- Each run is relatively simple since it typically handles only one data node
- Cons:
- Require the Logic App to have an HTTP trigger ; this might force exposing a Logic App that wouldn’t otherwise (e.g. scheduled)
- Monitoring is spread on a range of runs ; this might be tricky if multiple instances are invoked at the same time as runs will overlap
For the flat approach:
- Pros:
- Doesn’t require the Logic App to be exposed via HTTP
- Monitoring has a one invocation / one run unity
- Cons:
- Add complexity (until loop + variables) in the implementation
- Troubleshooting can be tricky as each run as a lot of data in them and it can be tricky to find the information in the loops
For us, there is no right or wrong approach. It really depends on the scenario.
Summary
We looked at two different ways to handle recursion in Logic Apps:
- We can keep the recursion and implement a parent-child pattern to get around the non-self call rule.
- Implement the recursion in loops within the same Logic App
One thought on “Handling recursivity in Logic Apps”