Problem

I recently created a Logic App that creates an account in an Azure tenant and e-mails the credentials to the user when the user adds him- or herself to a team in Microsoft Teams.

The Logic App had to look up the user in an Azure table storage account and if the user did not exist, I had to generate an initial password. If the user did exist, the initial password was retrieved from table storage. The user would have to change the password the first time logging in.

While this all functioned beautifully, the peculiar thing was that in all cases the user did not exist in the table storage, the lookup action resulted in a ‘NotFound’ status, which was to be expected, but it also reported ‘Failed’ as the action result.

I created parallel paths, the right path is triggered when the user exists, but this path is skipped in the example above. The left path in the logic app is triggered when the user does not exist. The ‘run after’ parameters have been set to run the task when the previous task has failed

This results in the path successfully completing all actions, but the end result in the portal is still reported as overall ‘Failed’, because the action of looking up the user in the table storage failed.

While the workflow still works and gets the job done, I really do not like the ‘Failed’ status because when the job actually fails it will not be noticed until it is too late.

Solution

There are two solutions to still report a ‘Succeeded’ status for the Logic app execution run.

1) Use a ‘Terminate‘ action reporting succeeded state.

There are two caveats in using the ‘Terminate’ action. The first is that the ‘run after’ conditions for the ‘Terminate’ action has to be set to include all conditions for both paths. The second caveat is that it will now always report success even if one of the actions in the parallel path fails.

2) Use a ‘Scope‘ action. The scope action allows us to report the last action in the scope instead of the failing retrieval of the entity in table storage.

Checking the status-code and assigning an EntityExists variable (which is initialized in the main flow) will result in a ‘Succeeded’ state for the scope now allowing the Logic Flow run to report status ‘Succeeded’.

The function expression for checking the status-code is:

int(outputs('Get_entity_from_table_storage')['statusCode'])

The ‘Get_entity_from_table_storage’ is the name of the action with the spaces replaced by underscores.

Conclusion

Both solutions will get the job done, but the cleanest option is using the ‘Scope’ action which is more work to implement but has the correct output in case of an actual exception.
Using the ‘Terminate’ action is a workaround, but needs to be used with caution.