[SalesForce] Flow Error – Apex CPU Time Limit Exceeded

I have a flow that is supposed to update multiple Account records and then triggers a process builder to update their related Opportunities. This happens at the start of the new fiscal year to set up the new pricing (which changes annually). I'm getting an error that says "Apex CPU time limit exceeded." I can't find any existing posts related to this error being caused by a flow.

Steps to Reproduce:

  1. Click a button that simply launches the flow.
  2. The flow first finds a Price Book of a certain Tier (custom picklist that exists on Price Book and Account) that has a Start Date of TODAY.
  3. Next, the flow finds all Accounts with the same Tier and updates a Price Book lookup field to match the Price Book that was just found.
  4. These steps are repeated for all 7 tiers. I couldn't process them all at once because I was getting SOQL errors, so I broke it down by Tier.
  5. The edit to the Account's Price Book field triggers a Process Builder, which find the Won Opportunities related to each Account and updates the Price Book field on the Opp, too.

Error:
If I have the Process Builder from step 5 turned off, steps 1-4 work just fine. However, if the Process Builder is activated, I'm getting the following error:

The flow tried to update these records: null. This error occurred: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY: npsp.TDTM_Opportunity: System.LimitException: Apex CPU time limit exceeded.

Also, if I run the flow via the Debug button in the flow builder, it all works, even if the Process Builder is activated.

Flow – Find Tier B Price Book

enter image description here

Flow – Update Tier B Accounts

enter image description here

Process Builder – Update Related Opps

enter image description here

Best Answer

The CPU time limit is a cumulative limit across the whole transaction. Essentially, what is happening is that your Flow, plus your Process invocations, plus the NPSP triggers that are run consequent upon the updates you are making, are taking too long to execute in a single transaction (10 seconds of CPU time).

Because the CPU time limit is a cumulative limit, it can be really tricky to put your finger on the cause without careful profiling using the Developer Console. What you see in any logs you might look at following the error is often just the proverbial straw that killed the camel, not the root cause.

Here, I feel fairly confident in saying that this is related to the volume of data that you are trying to update. You've got some moderately large number of Accounts in this Tier, and those Accounts have some number of Opportunities each. Triggers have to run on the updates of all of those records, and that consumes time.

The ultimate fix would probably be to move this functionality to a Batch Apex class, where you have considerably more control over which functionality runs when and can batch your data volume across multiple transactions. Given your client restrictions, I understand the Flow, but I think the result is going to push you to push the client to change their minds.

I previously wrote up an answer about using Wait events to segment a Flow into multiple transactions, and I think that might be something you could apply here.

My proposal - and I will admit that I've only tried this at a PoC level in my own org, and the success or failure will be pretty specific to your Flow - is that your Step 3 is the best place to intervene:

Next, the flow finds all Accounts with the same Tier and updates a Price Book lookup field to match the Price Book that was just found.

Since Accounts are changed after they've passed through this step, I think you could use a Wait element in a loop to query batches of Accounts, update them, Wait to start a new transaction, and then do the next batch.

Get Records in Flow doesn't support a LIMIT clause on its query, which makes this dramatically more difficult. The way I did it was to initialize a Text collection variable with letters of the alphabet, and query Accounts in a loop over that collection using a Starts With condition. Then a Wait skips to a new transaction after each letter.

Here's a rough outline:

flow diagram

Your actual Flow may need to use finer-grained criteria in its loop to break the transactions into small enough pieces. And, as cropredy rightly points out, it's assuming that breaking along Account lines will be enough. It might not be. If one Account has hundreds of Opportunities (or even dozens of Opportunities - in some orgs it doesn't take that much to bounce off the CPU time limiter), chunking by Accounts might not fix the issue anyway.

Honestly, this is a hideous solution. It's clunky as all get out, I don't think the performance will be very good, and it's not all that maintainable like a Flow should be because it's trying to handle data volume that's way too high. Plus, there's a high probability something will change down the road that'll result in the client coming back to complain about new limits problems.

A better solution would be a well-architected, configurable batch process that invokes declarative automation to run smaller pieces of functionality. I would try hard to sell that to the client myself.

Related Topic