The Issue
This is perhaps the edgiest of edge cases, but I wanted to share an approach to something I encountered recently. Managed Packages sometimes trigger asynchronous processes based on a record field change. As an example, consider the Renewal Opportunity generation process for the CPQ package which employs a Heroku callout. But how do we deal with failures that may be introduced by the Managed Package, since we cannot control as we usually would in an asynchronous process we control?
In the example of CPQ package, we can find record locks cause failures in the asynchronous job- even if processing with batch sizes of 1. This then leaves the field update initiating the managed package job still set, and so that record does not qualify again on the next run, which is an obvious problem.
The Example
To make the example more generic than CPQ, we’ll use a completely ridiculous use case on the Account object. Let us suppose something that would never happen – we have a program that every day takes Accounts of Industry = ‘Chemicals’ and updates them to Industry = ‘Agriculture’, because…why not? When an Account is set to ‘Agriculture’ the incredibly valuable ‘Farmers Fancy Automation’ managed package calls a method in a Queueable class to generate personalized sales materials, and then flips the CustomerPriority to ‘High’ on the Account. Unfortunately our managed package sometimes fails in its effort to generate personalized sales materials and then never writes back the CustomerPriority to one or more Accounts that were set in our daily update.
The Solution
Scheduled Flow has become a go-to for scheduling actions, and we’ll use that here. The uninteresting part is we will get all ‘Chemical’ Accounts, loop through them, and update them to ‘Agriculture’. Importantly, we’ll also write {!$Flow.InterviewGuid} to a FlowId field that has been added to the Account. This will let us easily find the Accounts that we’ve updated, so they can be checked later for successful completion.
Once we have our collection of records, we’ll update in the Flow. Immediately after, we use the Pause element, and will go into detail on what is happening there. Here is where we are to this point.
The Pause element can be restarted at a specific time declared in the Flow, based on a field value on a record, or upon receipt of a Platform Event. For our example, we’ll use the specific time as it works great for what we are doing. Let us suppose that the ‘Farmers Fancy Automation’ async process takes about 2 minutes to run typically, so we want to pause for 5 minutes to be sure it is completed before we check the results. We will create a formula field to set a value at 5 minutes in the future. Then we can set the restart to be 0 hours after this time, which will effectively cause a restart ~5+ minutes after the pause. Here is what that looks like:
And the Pause Element configuration to incorporate the formula.
After the pause is over, we want to re-query the Accounts that were updated in this Flow interview (using the FlowId), and where the update to CustomerPriority = ‘High’ did not take place.
For these records, we will set the Industry back to ‘Chemical’ so our scheduled Flow will pick them up again tomorrow. Note that you could instead try another update here, write an error message to the record for individual follow-up, notify someone of an error, etc. depending on the specific need and managed package behavior. For our use case, we loop through the records, set Industry to ‘Chemical’, assign to a Collection and Update back to their original values. These Accounts will then be ready on the new run.
The Summary
It’s rare to encounter this scenario, but I think scheduled Flow has a really nice way to deal with this in the use of a Pause element, and one that is not easily handled should we have initially triggered the asynchronous process through batch apex. In one interview we can handle the initial triggering of the managed package process, allow that process to run outside of our control, and then to check and handle the results. I hope you’ve found this a useful technique to consider should you ever encounter this scenario!