Platform governors prevent any one execution context from consuming excessive resources on the service, which could be detrimental to its users. Overall, an execution context cannot exceed 10 minutes, though within an execution context in practice, other limits would likely be reached before this.
For example, Apex code units executing within an execution context can only collectively execute for a maximum of 10 or 60 seconds depending on the context. Over the years, Salesforce has worked hard to consolidate what was once a confusing array of governors, which also varied based on a number of Apex code contexts. Thankfully, these days governors are much easier to follow and vary only based on the context being interactive or batch (asynchronous).
An important consideration for a packaged solution is the scope of a governor. In other words, does it apply only to the packaged code or for all code executing in the execution context? Remember that an execution context can contain code from other developers within the subscriber org or other packaged solutions installed.
Your package namespace acts as a container for some governors, which protects your code from limits being consumed by other packaged code (triggers for example) running in the execution context. The platform supports an unlimited number of namespace scopes within one execution context. For code that has not been deployed as part of a managed package, such as code developed directly in the subscriber org, there is a default namespace.
Code running in a namespace cannot exceed governors that are scoped by the namespace (as highlighted later in this chapter). Although an execution context can run code from unlimited namespaces, a cross-namespace cumulative limit is enforced. This is 11 times the specific per namespace limit. For example, a maximum of 1650 DML statements (150 per namespace) would be allowed across any number of namespaces. For more examples refer to the Execution Governors and Limits page in the Apex Developer Guide, in the sub-section entitled Per-Transaction Certified Manage Package Limits.
In reality 150 in my view is quite a lot of DML for a single namespace to be performing. If you are observing bulkification this would require you to be updating 150 distinct objects in one request! If that is the case and you are following DML bulkification, you may want to review your object model design to see if you can denormalize it a bit further. Though not documented, I suspect the 11 cumulative multiplier is likely based on the historic 10 namespace limit plus the default namespace.
You can see evidence of namespaces in play when you observe the debug logs within your packaging org. Just before each Apex code unit completes, notice how the LIMIT_USAGE_FOR_NS
section of the debug log is repeated for the default
and fforce
namespaces (your namespace will be different) as follows, allowing you to review the incremental usage of governors throughout the execution context:
13:47:43.712 (412396000)|CUMULATIVE_LIMIT_USAGE 13:47:43.712|LIMIT_USAGE_FOR_NS|(default)| Number of SOQL queries: 0 out of 100 Number of query rows: 0 out of 50000 Number of SOSL queries: 0 out of 20 Number of DML statements: 0 out of 150 Number of DML rows: 0 out of 10000 Number of code statements: 0 out of 200000 Maximum CPU time: 0 out of 10000 Maximum heap size: 0 out of 6000000 Number of callouts: 0 out of 10 Number of Email Invocations: 0 out of 10 Number of fields describes: 0 out of 100 Number of record type describes: 0 out of 100 Number of child relationships describes: 0 out of 100 Number of picklist describes: 0 out of 100 Number of future calls: 0 out of 10 13:47:43.712|LIMIT_USAGE_FOR_NS|fforce| Number of SOQL queries: 1 out of 100 Number of query rows: 1 out of 50000 Number of SOSL queries: 0 out of 20 Number of DML statements: 2 out of 150 Number of DML rows: 3 out of 10000 Number of code statements: 85 out of 200000 Maximum CPU time: 0 out of 10000 Maximum heap size: 0 out of 6000000 Number of callouts: 0 out of 10 Number of Email Invocations: 0 out of 10 Number of fields describes: 0 out of 100 Number of record type describes: 0 out of 100 Number of child relationships describes: 0 out of 100 Number of picklist describes: 0 out of 100 Number of future calls: 0 out of 10 13:47:43.712|CUMULATIVE_LIMIT_USAGE_END 13:47:43.412|CODE_UNIT_FINISHED|execute_anonymous_apex
Note that all governors are shown in the summary regardless of their scope; for example, the CPU time governor is an execution scope governor. This allows you to follow the consumption of the Apex CPU time across Apex code units from all namespaces. The Developer Console option provides some excellent tools to profile the consumption of governors.
When considering governors from a testing and support perspective, you should be aware of which governors are deterministic and which are not. For example, when profiling your application, this is being able to obtain the exact same results (such as the preceding results) from the debug logs from the repeated running of the exact same test. The following outlines examples of both types of governors:
In the CPU governor, the platform limits the length of time the execution context is allowed to spend executing the Apex code to 10 seconds for interactive context and 60 seconds for asynchronous context (for example, Batch Apex), though in practice the platform appears to exercise some tolerance. In contrast, the number of SOQL queries or DML statements is always constant when applied to a consistent test scenario.
As the CPU governor is non-deterministic, it should only be used as a guideline when testing. My recommendation is not to use the Limits.getCPULimit()
method as a branching mechanism between interactive and batch processing in your application. If you require this type of branching, focus on using aspects of your application such as selection criteria, number of rows selected, or some other configurable setting in the subscriber org perhaps via a Custom Setting.
You may want to consider testing certain governors within an Apex test context to monitor for changes in how many queries or DML are being consumed. Such tests can give you an early warning sign that inefficiency has crept into your code. Use the Limits
class methods to capture the before and after state of the SOQL and/or DML governors. Then, apply either a strict comparison of the expected usage (for example, 10 queries expected after the execution of the test) or a plus or minus tolerance to allow for code evolution.
The following table is a summary of key governors, their scope, and whether they are deterministic. Note that Salesforce is constantly monitoring the use of its service and adapting its governors. Always check for the latest information on governors in the Apex Developer Guide.
Governor |
Scope |
Deterministic |
---|---|---|
Execution context timeout |
Execution context |
No |
Apex CPU governor |
Execution context |
No |
SOQL queries |
Namespace |
Yes |
DML statements |
Namespace |
Yes |
Query rows |
Namespace |
Yes |
3.145.101.81