+ Start a Discussion
TinkerMeTinkerMe 

Resolving Apex CPU Time Limit Exceeded Error

Hi,

I am trying to resolve a conflict from the existing Apex code. We have enrolments coming in from a different system but some of these are not being pushed to salesforce because of Apex CPU time limit exceeded error. it is identified that these are coming from one of the codes. Any recommendations to improve the code to avoid this error?


Trigger:
trigger UpdateLocalObjectsFromEnlighten on enlighten__Enrollment__c (after insert, after update) {
  if(TriggerUtilities.bPreventTriggers == true)
  {
    return;
  }
    
  UpdateLocalObjectsFromEnHandler handler = new UpdateLocalObjectsFromEnHandler();
  handler.doIt(trigger.new, trigger.oldMap);
  
}

Handler:
public with sharing class UpdateLocalObjectsFromEnHandler {
    
    private string debugInfo = '';
    
    private void addDebug(string inf) {
        
        debugInfo += inf + '\n';
    }
    
    public void doIt(List<enlighten__Enrollment__c> newVals, Map<id, enlighten__Enrollment__c> oldVals) {
        // all items to update
        
        // we need the first and last activities related to each enrolment, if available
        Map<string, ActivityInfo> activities = new Map<string, ActivityInfo>();
        
        enlighten__Course_Activity__c[] cas = 
        [select enlighten__Activity_Time__c, enlighten__Enrollment__c, enlighten__Module__r.name
        from enlighten__Course_Activity__c
        where enlighten__Enrollment__c in :newVals
        and (enlighten__Module__r.name = 'Module 1 Quiz' or
            enlighten__Module__r.name like '%final exam%')];
        
        addDebug('found ' + cas.size() + ' records');
        
        for(enlighten__Course_Activity__c ca : cas) {
            addDebug(ca.enlighten__Enrollment__c);
            if(!activities.containsKey(ca.enlighten__Enrollment__c)) {
                activities.put(ca.enlighten__Enrollment__c, new ActivityInfo());
            }
            
            if(ca.enlighten__Module__r.name == 'Module 1 Quiz') {
                activities.get(ca.enlighten__Enrollment__c).Started = ca.enlighten__Activity_Time__c;
                addDebug('Module 1 Quiz @ ' + ca.enlighten__Activity_Time__c);
            } else if(ca.enlighten__Module__r.name.toLowerCase().contains('final exam')) {
                activities.get(ca.enlighten__Enrollment__c).Completed = ca.enlighten__Activity_Time__c;
                addDebug('Final Exam @ ' + ca.enlighten__Activity_Time__c);
            } else {
                addDebug(ca.enlighten__Module__r.name + ' not found');
            }
        }
        
        Set<id> toFind = new Set<id>();
        //System.debug('-------------- start');
        for(enlighten__Enrollment__c i : newVals) {
            if(!toFind.contains(i.id)) {
                toFind.add(i.id);
                System.debug('********* ' + i.id);
            }
        }
        
        enlighten__Enrollment__c[] recs = 
        [select id, enlighten__Contact__c, enlighten__Course_Score__c, enlighten__Percent_Complete__c, 
            enlighten__Course_Enroll_Date__c, enlighten__Course_Complete_Date__c, enlighten__Status__c, 
            enlighten__Course__r.enlighten__Course_ID__c, enlighten__Enroll_End_Date__c, enlighten__Course_Complete__c,
            enlighten__Last_Access__c
        from enlighten__Enrollment__c 
        where id in: toFind];
        
        //System.debug('-------------- ' + recs.size());
        
        Set<string> CourseNames = new Set<string>();
        Set<id> contacts = new Set<id>();
        
        // Loop and find all the SF course names (removing dash as needed)
        // and related contacts
        
        for(enlighten__Enrollment__c e : recs) {
            
            if(e.enlighten__Course__c == null) {
                //System.debug('enlighten__Course__c does not have a value (1)');
                continue;
            }
                    
            string CourseName = e.enlighten__Course__r.enlighten__Course_ID__c;
            
            if(CourseName != '' && CourseName != null) {
                //System.debug('enlighten course name:' + CourseName);
                integer dash = CourseName.lastIndexOf('-');
                if(dash > -1) {
                   CourseName = CourseName.substring(0, dash).trim();
                }
              
                if(!CourseNames.contains(CourseName)) {
                   CourseNames.add(CourseName);
                   //System.debug(CourseName);
                }
            
                if(!contacts.contains(e.enlighten__Contact__c)) {
                   contacts.add(e.enlighten__Contact__c);
                }
            } else {
                //System.debug('CourseName from enlighten is empty or null');
            }
        }
        
        // now get potential matches -- this might retrieve more than needed but will be filtered below
        List<Student_Course_List__c> scls = 
            [select id, Student__c, course__c, course__r.name, Percent_Complete1__c, Percent_Grade__c,
                Number_Grade__c, Actual_End_Date__c, Actual_Start_Date__c, Scheduled_End_Date__c,
                Last_Access__c, Enlighten_Enrollment_ID__c, Course_Status__c
            from student_course_list__c 
            where Course__r.name in:  CourseNames
            and   Student__c in: contacts];
        
        //System.debug('=============SCL ==' + scls.size());
        
        // create a composite key of student+course name
        Map<string, Student_Course_List__c> sclLookup = new Map<string, Student_Course_List__c>();
        for(Student_Course_List__c scl: scls) {
            sclLookup.put(scl.Student__c + scl.course__r.name, scl);
        }
        
        Map<id, Student_course_list__c> toUpdate = new Map<id, Student_Course_List__c>();
        // loop again and find any student courses registrations that match the enlighted update
        for(enlighten__Enrollment__c e : recs) {
            
            if(e.enlighten__Course__c == null) {
                //System.debug('enlighten__Course__c does not have a value (2)');               
                continue;
            }
            
            string cn = e.enlighten__Course__r.enlighten__Course_ID__c;

            if(cn != '' && cn != null) {            
                integer dash = cn.lastIndexOf('-');
              
                if(dash > -1) {
                   cn = cn.substring(0, dash).trim();
                }
                //System.debug('***********************************updating ' + cn);
                // update the fields
                if(sclLookup.containsKey(e.enlighten__Contact__c + cn)) {
                    Student_Course_List__c item = sclLookup.get(e.enlighten__Contact__c + cn);
                    addDebug('found ' + e.enlighten__Contact__c + cn + ' status is ' + item.Course_Status__c);
                    if(item.Course_Status__c != 'Released') {
                        item.Percent_Complete1__c = e.enlighten__Percent_Complete__c;
                        item.Percent_Grade__c = e.enlighten__Course_Score__c;
                        item.Number_Grade__c = e.enlighten__Course_Score__c;
                        //item.Enrollment_Status__c = e.enlighten__Status__c;
                        item.Actual_Start_Date__c = e.enlighten__Course_Enroll_Date__c;
                        item.Scheduled_End_Date__c = e.enlighten__Enroll_End_Date__c;
                        //item.Course_Completed__c = e.enlighten__Course_Complete__c; 
                        //item.Last_Access__c = e.enlighten__Last_Access__c; // not being used
                        //item.Percent_Complete__c = e.enlighten__Percent_Complete__c;
                        item.Enlighten_Enrollment_ID__c = e.id;
                        //item.Course_Complete__c = e.enlighten__Course_Complete__c; // handled by formula
                        
                        ActivityInfo act = activities.get(e.id);
                        
                        if(act != null) {
                            if(act.Started != null) {
                                item.Activity_Started__c = act.Started;
                                addDebug('setting Activity_Started__c ' + act.Started);
                            } else {
                                addDebug('no start date for ' + e.id);
                            }
                            if(act.Completed != null) {
                                item.Activity_Completed__c = act.Completed;
                                addDebug('setting Activity_Completed__c ' + act.Completed);                         
                            } else {
                                addDebug('no end date for ' + e.id);
                            }
                        } else {
                            addDebug('not found for ' + e.id);
                        }
                        
                        // if more than one update for this student course registration, use the most recent one
                        toUpdate.put(item.id, item);
                        //System.debug('updating SCR ' + item.id + ' contact ' + e.enlighten__Contact__c + ' ' + cn);
                    }
                } else {
                    
                    addDebug('did not find ' + e.enlighten__Contact__c + cn);
                }
            }
        } // end for

        update toUpdate.values();
        
        // now update number of courses on this day
        
        List<Student_Course_List__c> countCoursesEnrolled = new List<Student_Course_List__c>();
        Map<string, integer> sums = new Map<string, integer>();
        string lastKey = '';
        string key = '';
        integer courseCount = 0;
        
        scls = 
            [select id, Student__c, Count_of_Courses_Enrolled__c, 
             Enlighten_Enrollment_ID__r.enlighten__Course_Enroll_Date__c,
             Full_Time__c, Course__r.Course_Length_Days__c
            from student_course_list__c 
            where Student__c in: contacts
            and Enlighten_Enrollment_ID__r.enlighten__Course_Enroll_Date__c != null
            and Asynchronous__c = true
            order by Student__c, Enlighten_Enrollment_ID__r.enlighten__Course_Enroll_Date__c];      
        
        integer totalRecs = scls.size();
        integer recCount = 0;
        
        //System.debug('----totalRecs ' + totalRecs);
        
        // summarize by student + date + course length  
        for(Student_Course_List__c s2 : scls) {
            Date dt = s2.Enlighten_Enrollment_ID__r.enlighten__Course_Enroll_Date__c;
            
            key = s2.student__c + String.valueOf(dt) + String.valueOf(s2.Course__r.Course_Length_Days__c);
            //System.debug('key=' + key);
            recCount++;
            
            if(key != lastKey || recCount == totalRecs) {
                if(key == lastKey) {
                    courseCount++;
                }
                sums.put(lastKey, courseCount);
                courseCount = 0;
            }
            
            lastKey = key;
            //System.debug('lastKey=' + lastKey);
            courseCount++;
        }
        
        //System.debug('doing updates, if any===============');
        // now go through and see if any of the values need to be updated
        for(Student_Course_List__c s2 : scls) {
            Date dt = s2.Enlighten_Enrollment_ID__r.enlighten__Course_Enroll_Date__c;           
            key = s2.student__c + string.valueOf(dt) + String.valueOf(s2.Course__r.Course_Length_Days__c);  
            //System.debug('key=' + key);       
            integer sumVal = sums.get(key);
            //System.debug('sumVal=' + sumVal);
            if(s2.Count_of_Courses_Enrolled__c != sumVal) {
                s2.Count_of_Courses_Enrolled__c = sumVal;
                countCoursesEnrolled.add(s2);
            }
        }
        
        // Count_of_Courses_Enrolled
        if(countCoursesEnrolled.size() > 0) {
            update countCoursesEnrolled;
        }
        
        System.debug(debugInfo);
    }
    
    private class ActivityInfo {
        public string EnrolmentId { get; set;}
        public DateTime Started { get; set;}
        public DateTime Completed { get; set;}
    }
}

 
Kumaresan.ManickamKumaresan.Manickam
1) Try to avoid lot of for loop processing and inner for loops. Break the for loops wherever possible. Keep Map variables after pulling data from SOQL and use map to populate the different logic instead of re running the query multiple times in code.
2) Another thing is that, debug statements also takes reasonable processing time and avoid keeping debug lines until its not useful. I see lot of debug lines in the code.
3) SOQL dont have any impact with CPU time limit as salesforce excludes from the processing time. 
4) Keep this trigger execution in asyncronous processing(Queuable Or future) so get better govorner limits if the code still requires lot of processing time.

A good article from salesforce to avoid CPU time limit: https://help.salesforce.com/apex/HTViewSolution?id=000232681&language=en_US

Choose this answer as best reply if it's helpful.

Thanks.