Welcome to the third part of this series of blog posts on How to throw custom exceptions inside Logic Apps.
In this series of five blogs, I will cover throwing custom exceptions in Logic Apps. I will cover the following topics:
- Part I – Using default capabilities
- Part II – Using default capabilities – Extract failure information
- Part III (this article) – Using default capabilities – Avoiding too many condition actions
- Part IV – Using a child Logic App to throw a custom exception
- Part V – Using an API Management Throw Exception API
In this third approach, we are going to do a considerable fine-tuning of the previous approach, keeping the same capability to define custom error messages but redesigning the business logic in order to minimize the number of actions and optimize performance. In the end, we will see that the advantages in performance are significant and make it all sense to keep this strategy in mind whenever performance is a requirement to take into account.
Approach 3: Throw exceptions in Logic Apps with failure information: Avoiding too many condition actions
Taking our last solution as starting point, let us:
- Expand the Try Scope and delete everything that is inside:
- Delete Check if name is John condition.
- Still, inside the Try Scope delete:
- Delete Check if Age is Less than 18 condition.
- On our Initialize varResultMessage variable action, let’s add the following expression:
- if(equals(triggerBody()?[‘name’], ‘John’), if(less(triggerBody()?[‘age’], 18), ‘Invalid Age! You need to be older than 18.’, ‘Application accepted!’), concat(triggerBody()?[‘name’],’ is an Invalid Name!’))
This is indeed a more complex expression that, from a design point of view, will be more difficult to read and maintain if we compare it to the previous approach and the use of condition shapes in the design. But if we do an analysis of the expression, we will see that we are basically doing the same two conditions we were using in the previous approach:
- If the name is equal to John, then set the varResultMessage as Application accepted!
- Otherwise:
- If Age is less than 18, then set the varResultMessage as Invalid Age! You need to be older than 18.
- Otherwise, set the varResultMessage as <name> is an Invalid Name!’
Now, inside our Try Scope we need to do the following actions:
- Add the following Condition action into the design with the following configuration:
- varResultMessage is not equal to Application accepted!
- Inside the True branch, add a new Compose action and define the inputs parameter with the following expression:
- int(‘__ERROR__’)
- Leave the False branch empty and save the solution.
Now if we try our solution, we will end up having the same results.
The most significant advantages of this solution are performance and less business logic complexity.
If we now go back to the Run History of approach 2 and analyse the Duration of all executions and calculate the average of them, we have an average processing time of 1.7 seconds:
Which in itself is not bad, but if we check our process, we realize that we are not actually invoking external systems; we are just doing validations. That means that we should expect a better response time.
Now, if we go to the Run History of the third approach and do the same analysis, we have an average processing time of 862 milliseconds!
That is less than a second! You can see that some of them take only around half a second. If you compare this with the second approach based on the execution, we see that the best performance time of approach 2 was 924 milliseconds, so almost a second and worst scenario was 3.09 seconds compared to 829 milliseconds on this approach.
In terms of business process complexity:
- In approach 2 we had to use a total amount of 15 shapes/actions.
- In approach 3 we only used only 10 shapes/actions. That means fewer 5 shapes/actions.
Nevertheless, it has the same critical drawbacks as the previous approach:
- We are not throwing a custom exception. Instead, we are forcing an error to happen.
- Add more complex logic to the catch scope.
- It is not a global solution, so for each Logic App, we need to implement this logic continually.
So, again I can probably say that this solution is suitable for a small business Logic, small solution, or for clients that have a small footprint in Azure.
I hope you enjoy and stay tuned for part IV.