Handling recursivity in Logic Apps


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:

  1. Using a simple indirection to work around the limitation.
  2. 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.

Recursion

Let’s look at an example:

Deploy button

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:

parent-app

  1. Let’s select the parent-app and go to its designer view
  2. Let’s open the trigger When a HTTP request is received
  3. We can copy its HTTP POST URL
    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:

HTTP Post

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:

History

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

The payload should look like:

[
    {
        "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:

Deploy button

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:

Post flat

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:

Flat History

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:

  1. We can keep the recursion and implement a parent-child pattern to get around the non-self call rule.
  2. Implement the recursion in loops within the same Logic App

One thought on “Handling recursivity in Logic Apps

Leave a comment