azureazure-logic-appsazure-logic-app-standard

Logic App until loop does not exit with failure if the condition is not met after timeout period


I have a very simple logic app here.

a get API on server status, parse the body. and until loop that will keep checking until the server status return not ready and exits the loops to return the status.

{
  "type": "Until",
  "expression": "@equals(variables('CheckVar'),'Not Ready')",
  "limit": {
    "count": 5,
    "timeout": "PT1M"
  },
  "actions": {
    "HTTP-copy": {
      "type": "Http",
      "inputs": {
        "uri": "https://management.azure.com/subscriptions/<SubId>/resourceGroups/PGSQL-POC/providers/Microsoft.DBforPostgreSQL/flexibleServers/?api-version=2023-06-01-preview",
        "method": "GET",
        "authentication": {
          "type": "ManagedServiceIdentity",
          "identity": "/subscriptions/<SubID>/resourcegroups/PGSQL-POC/providers/Microsoft.ManagedIdentity/userAssignedIdentities/PG-Backup-Restore-SPN-MI"
        }
      }
    },
    "Parse_JSON-copy": {
      "type": "ParseJson",
      "inputs": {
        "content": "@triggerBody()",
        "schema": {
          "type": "object",
          "properties": {
            "sku": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "tier": {
                  "type": "string"
                }
              }
            },
            "properties": {
              "type": "object",
              "properties": {
                "fullyQualifiedDomainName": {
                  "type": "string"
                },
                "version": {
                  "type": "string"
                },
                "minorVersion": {
                  "type": "string"
                },
                "administratorLogin": {
                  "type": "string"
                },
                "state": {
                  "type": "string"
                },
                "availabilityZone": {
                  "type": "string"
                },
                "storage": {
                  "type": "object",
                  "properties": {
                    "storageSizeGB": {
                      "type": "integer"
                    },
                    "autoGrow": {
                      "type": "string"
                    },
                    "tier": {
                      "type": "string"
                    },
                    "iops": {
                      "type": "integer"
                    }
                  }
                },
                "authConfig": {
                  "type": "object",
                  "properties": {
                    "activeDirectoryAuth": {
                      "type": "string"
                    },
                    "passwordAuth": {
                      "type": "string"
                    }
                  }
                },
                "backup": {
                  "type": "object",
                  "properties": {
                    "backupRetentionDays": {
                      "type": "integer"
                    },
                    "geoRedundantBackup": {
                      "type": "string"
                    },
                    "earliestRestoreDate": {
                      "type": "string"
                    }
                  }
                },
                "network": {
                  "type": "object",
                  "properties": {
                    "publicNetworkAccess": {
                      "type": "string"
                    }
                  }
                },
                "highAvailability": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "type": "string"
                    },
                    "state": {
                      "type": "string"
                    }
                  }
                },
                "maintenanceWindow": {
                  "type": "object",
                  "properties": {
                    "customWindow": {
                      "type": "string"
                    },
                    "dayOfWeek": {
                      "type": "integer"
                    },
                    "startHour": {
                      "type": "integer"
                    },
                    "startMinute": {
                      "type": "integer"
                    }
                  }
                }
              }
            },
            "location": {
              "type": "string"
            },
            "tags": {
              "type": "object",
              "properties": {
                "ElasticServer": {
                  "type": "string"
                }
              }
            },
            "id": {
              "type": "string"
            },
            "name": {
              "type": "string"
            },
            "type": {
              "type": "string"
            }
          }
        }
      },
      "runAfter": {
        "HTTP-copy": [
          "SUCCEEDED"
        ]
      }
    },
    "Set_variable": {
      "type": "SetVariable",
      "inputs": {
        "name": "CheckVar",
        "value": "@body('Parse_JSON-copy')?['properties']?['state']"
      },
      "runAfter": {
        "Parse_JSON-copy": [
          "SUCCEEDED"
        ]
      }
    }
  },
  "runAfter": {
    "Initialize_variables": [
      "SUCCEEDED"
    ]
  }
}

Until Loop ConditionSet VariableParse JSON-Copy body my issue is that if the server is alway ready, and the loop never meets the condition to exit. It should timeout after 1 minute and fail because the condition never met. However, when I run this, I see that its succeeding after the timeout period with status set to ready, which mean the loop never met the condition(Not ready) to exit. Until loop exit with success even though the condition is not met

Shouldn't it fail here instead of succeed?

It should exit with failure if the condition is not met within the timeout or retry period. instead the loops exits with success and moves onto the next step

additional Images from recent run

Parse JSON-Copy body response Variable being set to ready as expected Until loop exited with success even though the status is Ready (the condition should exit with success only when status is Not Ready)


Solution

  • my issue is that if the server is alway ready, and the loop never meets the condition to exit. It should timeout after 1 minute and fail because the condition never met. However, when I run this, I see that its succeeding after the timeout period with status set to ready, which mean the loop never met the condition(Not ready) to exit. Until loop exit with success even though the condition is not met

    Shouldn't it fail here instead of succeed?

    The Until loop in Logic Apps won’t fail automatically if the exit condition is never met. It will time out or complete its iterations and still return “Succeeded”. To fail the workflow when the condition isn’t met, you must explicitly check and terminate it after the loop.

    Initialize a variable (e.g., CheckVar) outside the loop and inside the Until loop call your API.

    Set CheckVar using:

    @body('HTTP-copy')?['state']
    

    Use exit condition:

    CheckVar is equal to 'Not Ready'
    

    After the loop, add a Condition:

    If CheckVar != 'Not Ready'
    

    The Terminate action will fail the flow. This ensures your Logic App fails clearly when the state never reaches the desired value, rather than succeeding.

    Initialize variable:

    {
      "name": "Initialize_variable",
      "type": "InitializeVariable",
      "inputs": {
        "variables": [
          {
            "name": "CheckVar",
            "type": "string",
            "value": ""
          }
        ]
      }
    }
    

    Until loop:

    {
      "name": "Until_Check",
      "type": "Until",
      "inputs": {
        "condition": "@equals(variables('CheckVar'), 'Not Ready')",
        "actions": {
          "HTTP-copy": {
            "type": "Http",
            "inputs": {
              "method": "GET",
              "uri": "<YOUR_API_ENDPOINT>"
            }
          },
          "Set_variable": {
            "type": "SetVariable",
            "inputs": {
              "name": "CheckVar",
              "value": "@body('HTTP-copy')?['state']"
            }
          }
        },
        "limit": {
          "timeout": "PT1M",
          "count": 5
        }
      }
    }
    

    Condition after loop:

    {
      "name": "Check_After_Loop",
      "type": "If",
      "expression": "@not(equals(variables('CheckVar'), 'Not Ready'))",
      "actions": {
        "Fail_Flow": {
          "type": "Terminate",
          "inputs": {
            "status": "Failed",
            "message": "Condition not met after retries. Failing the workflow."
          }
        }
      }
    }
    

    Images:

    enter image description here enter image description here enter image description here enter image description here