To ensure optimum performance in Workflows, follow best practices for building your flows.
The Workflows API endpoint allows an external client to invoke a flow over HTTP. It is a powerful feature because it expands flows beyond those started by the built-in connector library. However, these flows require attention to ensure they successfully complete. See About invoking an API endpoint flow.
The primary challenge with the use of the API endpoint is that the Workflows engine does not make latency guarantees. This means that although flows run fast most of the time, sometimes flow execution times will vary by 10X or more.
Because the API endpoint will close its connection to a client at 60 seconds, a flow will fail if it takes any longer than that. In some cases, an HTTP client that invokes an API Endpoint flow could have an even lower timeout than the default API timeout. For example, Okta inline hooks have a default timeout of 3 seconds.
A best practice when working with API Endpoint flows, is to structure your flow to be processed asynchronously. This means the caller (HTTP client) should not need to wait for a specific response.
This is especially important when integrating with Okta hooks. For instance, many flows that start off using the synchronous registration or import inline hook can be restructured by starting a flow with Okta events using the asynchronous User Created and User Okta Profile Updated event cards. Moving to the asynchronous pattern is more advantageous for both systems. A common example is recording the registration and import of a new user in a third system. If there isn’t a critical need for it to be there instantaneously, the asynchronous pattern gives a much better experience.
One way to manage the risk of a timeout is to close the HTTP connection as quickly as possible. One best practice is to add the API Connector Close card as the first card in the flow. This allows the Workflows engine to immediately release its HTTP connection to the caller (HTTP client). Afterwards, the Workflows engine will asynchronously process the rest of the flow. See Close.
Another best practice is to use the combination of Call Flow Async and Flow Control Return Raw cards. They allow you to start processing work asynchronously and have fine-grained control over the HTTP response. See Call Flow Async and Return Raw.
If a client requires a synchronous response, pay extra attention to flow architecture to make sure you are not introducing unnecessary latency and timeout risk.
Avoid external network calls. Calls can take hundreds of milliseconds of latency, not including the time the external service takes to process data. External calls occur in connector cards as well as HTTP cards. If you must make external network calls, create a helper flow and use the Call Flow Async card to move the calls out of the synchronous flow.
Once the response is ready, immediately return it. You can use the API Connector Close card to return a value while the rest of the flow continues processing.
The Workflows engine executes many smaller actions more efficiently than fewer large actions. Flows that use excessive memory may be throttled or stopped to protect system resources. These are important techniques to improve flow performance and avoid out-of-memory, throttling, execution delays, or other issues.
When you can build multiple asynchronous flows, the Workflows engine will intelligently schedule the work to complete your flow as fast as possible. If you have a large amount of asynchronous work to do from your parent flow, the best practice is to use the Call Flow Async card. This card will continue processing your parent flow while the engine concurrently executes the helper flow that is specified as the input.
If you have a large list of items and need to process each item in a list, the best practice is to use the List For Each - Ignore Errors card. This card will take a list and run a helper flow for each item in that list, with optional concurrency. While the card is labeled “Ignore Errors”, that is really from the parent flow perspective. You can handle errors in your helper flows. See For Each - Ignore Errors.
If you only need to process a subset of items in a list, the best practice is to filter them using the List Filter card instead of stopping a helper flow early. See Filter.
While helper flows are preferable to doing a lot of processing in a single large flow, keep in mind that the creation and execution of helper flows is overhead. If you can avoid them for jobs that you don't need to process, then your flow will run more efficiently.
When operating on a list of items and using a For Each card, the best practice is to pass only the data that the helper flow needs in the With the following values section. You can pull individual data items out of the list you are iterating over by using the interface to pick the individual item to pass. For example, if operating on a list of users, pass only the single user’s required fields into the helper flow instead of the entire user object.
Streaming actions will take lists of results and automatically execute a helper flow for each item asynchronously. This process is optimized so the parent flow paginates through the data and creates the helper flows with low memory consumption.
Be mindful that non-streaming result set options lead to increased flow memory usage. Cards that feature the option Stream Matching Records in the Result Set field support streaming actions. The Find Users, List Users with Search, and List Users Assigned to Applications action cards for the Okta connector return lists and support streaming. See Set up the stream matching option with a helper flow.