Right about now, most of the Walking Dead fans are fondly reflecting back to the “good ol’ days” when the chief threat to our zombie-apocalypse family was the Woodbury Governor. Negan’s introduction has certainly shaken things up…

Fortunately for us Salesforce users, we don’t have to worry about actual zombies. Even better, we have cyber-security warriors at Salesforce protecting us from the potential Negan’s out there. We still have a Governor. Salesforce will say this Governor is needed, and they are correct. However, like the series, the Governor seems to pop-up out of nowhere. You could be doing everything right, but it doesn’t matter — the Governor shows up and rains on your parade.

For the most part, the obstacles presented by Salesforce’s governor limits can be avoided. Many of us go to great pains to ensure we are adequately protected against them. But there is one governor limit that you’ll find is not so easy to protect against: maximum CPU time on the Salesforce servers.

The CPU Limit Issue

Unlike the other governor limits, where sound development practices can mitigate your chances of encounter, the CPU limit issue can be difficult to evade. There are certainly measures out there to protect yourself against this (to which I will get to momentarily); but chances are you had a budget and a deadline when developing your application. Those two constraints meant you focused on developing your product for the most-likely vs. not every instance regardless their likelihood. At CodeScience, we can build your app to withstand a nuclear blast, but is it practical for you to pay for such insurance?

While hindsight is of little comfort when facing the issue in the present, it bears reminding that you’re working in a shared space for execution time in your customer’s org. And this execution time is being tracked on a per transaction basis.

When your code makes an update, to Contacts for example, this event will execute every workflow and trigger in that customer’s org that is associated with Contact updates; whether they are part of your application or not. And if any of those other operations happen to update another object’s record, then the workflows and triggers built for that object’s records start up. As you can imagine, this cascading event can get precarious quick, fast, and in a hurry. Salesforce is timing you on that initial Contact update, and holding you to account for all those other operations that are being called up because of your transaction. Since resources are both shared and limited, to make this multi-tenant architecture that is Salesforce function properly, they have to kill operations that appear to be cascading out of control — regardless if they are or not.

Possible Solutions

Smaller Batch Sizes

One possible solution to safeguard against this would be introducing smaller batch sizes. Initially this will help reduce the amount of transactions you are creating and will hopefully keep you within the CPU limit. But, this is not a guarantee.

Limit Method

Another option you could try leveraging would be the Limit method, which enables you to monitor if you’ve got time remaining to process your part of the batch synchronously. If you don’t, then consider firing off an @future job to do your work in another process. Of course, this also introduces you to an entirely new set of transaction limits.

@future

When using @future, you need to consider that you cannot control when that operation will execute. Therefore it can very likely execute in an order different than when it was called. This may be fine, if you daisy-chain your batches off of one another. But, could be problematic if you need this @future operation to occur before another operation starts.

Additionally, the @future option has limits to its usage within a 24 hour period. You are limited to 200 @future calls per license per org. When your operation is running, it’s running as the user that initiated the operation. You don’t know how many @future calls they have left when you start making these calls. And, before you go there, NO, it doesn’t matter if you have this operation as a scheduled batch job for 2:00 am thinking that by that time the user may have a clean slate given, it’s a new day. Nice try. Salesforce is tracking that value as the past 24 hours from the moment you initiated the @future call as that user.

Queueable Apex

Finally, you can consider leveraging the Queueable Apex option. Queueable Apex is like the @future method, but it differs in a few key areas:

  • When you enqueue apex, you are given a Job ID, which you can monitor like a scheduled batch job.
  • You can call an enqueued job from another enqueued job, in fact, as of Spring 15 there are no limits to how many you can chain together. So if you need to run operations in a given order, you can.
  • Unlike @future methods, you are not restricted to primitive data types.

The Queued Apex job, then gets picked up when the resources are available to manage your operation. So if you are using the limit method mentioned above, and notice you are encroaching on CPU limits, you can leverage the Queueable interface to schedule that job at a later time, and chain do the same for the other dependent operations — so they can run in the required sequence but at a point in time where the system has the resources to do so.

However, you can still run into problems.

Case in point: your customer’s org is crowded with hundreds of users managing hundreds of thousands of accounts. And this org has dozens of custom flows and apex triggers levied against the standard objects; in conjunction with a myriad of applications that also bring their own source of flows and apex triggers with them. The Queueable interface could still be ineffective, as you would essentially be constantly throwing your operations into the Queue and never executing.

I would actually argue that is the worst situation to be in. Because your operations would never execute and it would never fail. So how do you know if the issue is that the customer’s org needs to be cleaned up, or that you did something wrong in the coding of your operation?

While attempting to evade one issue, you can very easily thrust yourself into a whole new batch of governor limits; or worst yet, find yourself with zombie apex operations (operations that should have died and failed, but yet are still alive and consuming resources). So, as I mentioned from the start, you could spend a lot of money building your application to account for this CPU time limit governor; but that doesn’t insure you are protected from it.

What To Do?

In the end you need to understand why this is happening. If you’ve been doing everything right, then the likely answer is that the customer’s org is too crowded. Experience has painfully shown me that this sort of occurrence is most prevalent when coding DML operations against standard objects. My recommendation is to steer clear of that if at all possible. If you just cannot, then do so extremely sparingly.


At CodeScience we have deep expertise gained from building 250+ apps for the AppExchange. We are here to help you succeed. Contact our team today to schedule a time to talk.