With the following code, I'm getting an Apex CPU time limit exceeded error:
List<Lead> untouchedLeads = [SELECT id
FROM Lead
WHERE Days_Since_Last_Touch__c > 2
AND CreatedDate = LAST_N_WEEKS:6
AND Status = 'Attempting'
AND Owner.Type = 'User'
ORDER BY CreatedDate DESC NULLS LAST LIMIT 508];
if(untouchedLeads.size() > 0) {
// find ID of distribution queue
List<Group> distQueues = [SELECT Id
FROM Group
WHERE DeveloperName = 'Distribution_Queue'
AND Type = 'Queue'
ORDER BY CreatedDate DESC NULLS LAST LIMIT 1];
if(distQueues.size() > 0) {
//assign untouched leads to distribution queue
Id distQueueId = distQueues[0].id;
for(Lead untouchedLead : untouchedLeads){
untouchedLead.Ownerid = distQueueId;
}
update untouchedLeads;
}
}
Should I not be updating a list like that?
Here is our only update lead trigger code that's not part of a managed package:
/******************/
/* after update */
/******************/
if (trigger.isAfter && trigger.isUpdate && triggerContextUtility.isFirstRun()) {
// indicates this ran
system.debug ('***** enter leadTrigger after update *****');
// if lead is updated by API or System User
if(user=='API User' || user=='System User') {
for(Lead l: trigger.new) {
Lead oldLead = Trigger.oldMap.get(l.Id);
Boolean oldLeadOwnedByUser = oldLead.Owner.Type.equals('User');
Boolean newLeadOwnedByQueue = l.Owner.Type.equals('Queue');
if (oldLeadOwnedByUser && newLeadOwnedByQueue){
Date four_days_ago = Date.today().addDays(-4);
Date seven_days_ago = Date.today().addDays(-7);
String owneridstring = l.OwnerId;
system.debug ('leadTrigger after update activeOrg running user: ' + user);
system.debug ('leadTrigger after update activeOrg lead id: ' +l.Id);
system.debug ('leadTrigger after update activeOrg org id: ' +l.Org_ID__c);
system.debug ('leadTrigger after update activeOrg IsConverted: ' +l.IsConverted);
system.debug ('leadTrigger after update activeOrg IsDeleted: ' +l.IsDeleted);
system.debug ('leadTrigger after update activeOrg Scammer__c: ' +l.Scammer__c);
system.debug ('leadTrigger after update activeOrg CustomerStatus__c: ' +l.CustomerStatus__c);
system.debug ('leadTrigger after update activeOrg Hiring_Plan__c: ' +l.Hiring_Plan__c);
system.debug ('leadTrigger after update activeOrg ZipHR_Demo_Request_Time__c: ' +l.ZipHR_Demo_Request_Time__c);
system.debug ('leadTrigger after update activeOrg ZipHR_Benefits_Setup_Request_Time__c: ' +l.ZipHR_Benefits_Setup_Request_Time__c);
system.debug ('leadTrigger after update activeOrg ZipHR_Self_Service_Benefits_Start_Time__c: ' +l.ZipHR_Self_Service_Benefits_Start_Time__c);
system.debug ('leadTrigger after update activeOrg Free_Trial_Start_Time__c: ' +l.Free_Trial_Start_Time__c);
system.debug ('leadTrigger after update activeOrg LastActivityDate: ' +l.LastActivityDate);
system.debug ('leadTrigger after update activeOrg seven_days_ago: ' +seven_days_ago);
system.debug ('leadTrigger after update activeOrg OwnerId: ' +l.OwnerId);
// lead qualifies for auto conversion if
// lead is a paying org
// lead is not on a free trial
if(
//trigger.oldMap.get(l.Id).Hiring_Plan__c != l.Hiring_Plan__c &&
l.Org_ID__c != null
&& l.IsConverted == false
&& l.IsDeleted == false
&& l.Scammer__c != 'scammer'
&& l.CustomerStatus__c == 'paying'
&& l.Hiring_Plan__c != null
&& !l.Hiring_Plan__c.contains('free')
&& !l.Hiring_Plan__c.contains('trial')
&& (l.Free_Trial_Start_Time__c < four_days_ago || l.Free_Trial_Start_Time__c == null)
/*
&& ( (l.LastActivityDate == null
|| l.LastActivityDate < seven_days_ago)
|| owneridstring.startsWith('00GG')
)
&& l.ZipHR_Demo_Request_Time__c == null
&& l.ZipHR_Benefits_Setup_Request_Time__c == null
&& l.ZipHR_Self_Service_Benefits_Start_Time__c == null
&& (l.Free_Trial_Start_Time__c < seven_days_ago
|| l.Free_Trial_Start_Time__c == null)
*/
) {
activeOrgMap.put(l.Org_ID__c,l);
}
}
}
system.debug ('***** leadTrigger after update activeOrgMap size: '+activeOrgMap.size());
}
// prevent multiple recursions
triggerContextUtility.setNumOfRuns();
system.debug('**** leadTrigger after update number of runs: ' + triggerContextUtility.getNumOfRuns());
// if trigger already ran, setFirstRunFalse
TriggerContextUtility.setFirstRunFalse();
system.debug('**** leadTrigger after update is first run: ' + triggerContextUtility.isFirstRun());
// return number of soql queries in this execution context so far
system.debug('leadTrigger after update, queries used in this apex code so far: ' + limits.getQueries());
} /**** end after update ****/
Could something in there be the problem?
Best Answer
The first piece of code you posted will use an amount of CPU time that depends on how many records are matched and so is inherently at risk of hitting CPU and heap limits no matter how much optimisation you do.
A mechanism the platform provides to handle this problem is batchable Apex where you can place the query in the
start
method and have the work done in multiple transactions in theexecute
method where each transaction is passed a limited number of records - you can pick how many and so stay well below the governor limits. The processing is done asynchronously and for example can be scheduled to run every night (which makes sense for logic like this based on days).PS
To start the batch processing (where the second parameter is how many records to process at once and can be from 1 to 2,000):
with the batchable class: