The Try-Catch Pattern
Following the idea of defensive programming or as I like to call it for Logic Apps (being low code): defensive processing, it is considered good practice to wrap your workflows in a try-catch pattern to handle the unexpected. The pattern makes use of a mixture of Run After conditions and the Scope block.
- Run After Conditions | used to define the execution order based on the state of the previous action or scope
- Scope Block | provides the ability to group a series of actions. If any action within the scope fails, the whole scope will fail (unless handled via other means)
By placing your actions within a “try” scope with the assumption that each action will run after the success of the previous, if there is an action failure, the scope will fail also.
Using the Run After conditions on either a proceeding action or scope, you can “catch” any has failed, is skipped, or has timed out
states from the “try” scope. In effect this makes up your simple try-catch block.
Example
It is possible once you have entered into the catch scope to retrieve details of the resulting try scope by using the expression @result('Scope-Try')
. The expression will provide an array of all the actions and their details including if they were successful or failed with a given exception message.
This is really useful but how does it hold up when nested you may ask…
Nested Try-Catch Scopes
Nested try-catch scopes can be handy when you have smaller segments of the larger workflow that can be tried as a group; preventing unnecessary complexity in handling issues and failures later in the workflow or as a whole.
Example
This example still has its overarching try-catch due to the possibility of either sub catches containing actions that can fail, be skipped, or time out.
Nesting try-catch scopes offers the same capabilities as un-nested. However, there are caveats to remember when nesting in this way:
- Complexity | readability and maintainability is always paramount when designing workflows.
- Make sure to appropriately and consistently title actions and scopes.
- Add comments, especially on scopes as this can aid in describing the processing and functionality that sits within.
- Intentional flow review | given the added complexity through nesting and run after configurations, thorough review and testing of processing flow should be conducted.
- A method of doing this is to test/mock outputs on actions.
- Handles the unexpected | as with the single try-catch, this is not a method in handling non-“happy path” results from processing, rather the unexpected failures, skips, or timeouts.
As referred to in the last point in the caveats, if the try-catch both singular and nested aids in the unexpected, how can I add to this pattern to help with handling “un-happy” paths. This cues the Compensating Transaction pattern…
Compensating Transaction Pattern
The Compensating Transaction pattern is useful when you are trying to attain an eventually consistent operation that consists of multiple steps. If one or more of the steps fail, this pattern can be used to undo the steps performed.
One of the most basic forms of compensation or undo is to notify for manual remediation. This is the scenario that I will use as an example.
Scenario
Let’s assume that a taxi booking process needs to be automated as a logic app workflow. There are four steps involved in this process:
- Check to see if the customer is an existing customer, and if so obtain an enriched form of their details from our system.
- Check if the time slot is available with a local driver.
- If the time slot is available, book the time slot with the local driver.
- Send a notification to the customer regarding details of the booked time slot and their driver.
If there are any problems with processing these four steps, a notification will need to be sent for manual remediation. This must include:
- The steps that were successful
- The step that was not able to be performed
- The steps that were skipped after the one that failed to be processed
In this scenario and example, the use of the try-catch pattern (nested) is used to catch the unexpected problems in processing. The addition of the Condition action allows us to perform process validation (the action may have succeeded, but did it return the result we desired?). The example further uses the Condition action to validate if the workflow should continue onto the next processing step given the previous may have failed.
Example
The example shows a subset of the steps implemented as the rest are a repeat demonstration.
Given this workflow design, we can process faults in a controlled manner both expected and unexpected. We can control which processing steps should be performed given an error may have occurred, and we can through our transaction log give a full account allowing for full remediation.
There are caveats to remember when implementing this pattern and example:
- Complexity | readability and maintainability is always paramount when designing workflows.
- Make sure to appropriately and consistently title actions and scopes.
- Add comments, especially on scopes as this can aid in describing the processing and functionality that sits within.
- Intentional flow review | given the added complexity through nesting, conditions, and run after configurations, thorough review and testing of processing flow should be conducted.
- A method of doing this is to test/mock outputs on actions.
Hope this helps and have fun.