When to use Azure Logic Apps Stateless Execution
Azure Logic Apps provides a rich debug and reliability experience for developers when building Consumption-based logic apps. This experience also applies to stateful Standard logic apps. The reason for a rich debug and reliability experience is possible is due to state being persisted in external storage. This allows developers to “follow the bread-crumbs” by viewing logic app execution Run History. Since we have state being persisted, we can have long running processes as state can be persisted and re-hydrated as necessary.
The downside to this durability, is there are some performance impacts as making calls to external storage are costly, from a performance perspective. Stateless logic apps do not have their state persisted to external storage, so there are some performance benefits available. If stateless logic apps can improve performance, what are the associated tradeoffs? Here are some:
- You will lose the ability to view a logic app’s Run History. This means seeing the input/outputs for each action will be unavailable. Do note, that you can temporarily enable debugging, but there will be some performance impacts by doing so. You may want to do this when you first deploy your logic app to ensure it is working as expected and then you can disable it.
- Logic apps execution should be short running. While consumption/stateful executions can last for days, stateless need to complete their execution within 5 minutes. Stateless executions run in memory and as a result need to be short-lived, otherwise you risk platform stability by potentially running out of available memory.
- Message size should be less than 64kb. To avoid running into out of memory exceptions, message sizes should be small. If you have requirements for larger file sizes, you should consider stateful executions.
- Stateless logic apps have synchronous execution. If you need to use an async-http pattern, you should consider using stateful execution.
- Not all triggers are supported in stateless executions: Stateless workflows currently support only actions for managed connectors, which are deployed in Azure, and not triggers. Triggers must natively run in the Azure Logic Apps runtime which largely leaves us with Request, Event Hubs or Service Bus triggers.
Aside from the constraints that we have just discussed, another consideration is to look at the type of interaction that is involved in your interface. For example, if we have a lot of read operations where we need to retrieve reference data before we can perform a write operation, using stateless execution can be advantageous for us. These types of scenarios are popular when integrating with CRM systems like Dynamics 365 or Salesforce.
Let’s take the same use case/scenario and then be able to compare/contrast the performance of stateful/stateless logic apps. To better understand the performance differences, I created the same logic app but deployed it as both a stateful and a stateless logic app.
The logic app will receive an HTTP request and declare a float variable called total. We will then query Dataverse looking for the 15 most recent records that contain invoice information. Next, we will loop through each record and add the current value to our total variable and then return the result back to the caller.
To make the test as fair as possible, I submitted 3 requests sequentially to allow for the service to “warm-up” for both stateful and stateless. I subsequently submitted 5 requests (sequentially) and recorded the results. I performed the stateful tests first, followed by the stateless. The results are below:
While this test is quite simple and results may vary by submitting more concurrent load to the services, it does give you a reasonable representation of what to expect. For some interfaces, a variance of 5 seconds may not be overly relevant, but if you have an end user waiting for a request to complete, every second matters.
In this post we discussed some of the characteristics of stateless logic apps and some scenarios where stateless may be applicable. Ultimately, it is good to have options that allow you to best solve the business requirements. Whenever you have low-latency requirements where Run History isn’t required, stateless execution should be considered. However, when you have strict reliability requirements, or long running processes, stateful execution is likely a better option.