function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Ken Tallman 10Ken Tallman 10 

Failed to invoke future method; Apex CPU time limit exceeded

I got the following email from SF identifying an error from an Apex class, but the user did not report any problems. Note that I'm not a developer and all Apex code was written by my predecessor. 

Apex script unhandled exception by user/organization:
005j0000000RbTR/00Dj0000000Jnvo

Failed to invoke future method 'public static void processIntakes(Set<Id>)'
on class 'IntakeClass' for job id '7070a00007TgpBu'

caused by: System.LimitException: Apex CPU time limit exceeded

Class.IntakeClass.checkExistByDate: line 167, column 1
Class.IntakeClass.setUpIntakeStatMonthRecords: line 241, column 1
Class.IntakeClass.processIntakes: line 20, column 1
Dushyant SonwarDushyant Sonwar
Hi Ken,

Could you post your whole code of 'IntakeClass' ? There is some logic in this class that is taking cpu time. You may need to optimize the code for this.

 
Dev_AryaDev_Arya
Hi Ken,
This is obvious that the process is taking more that allocated time. The Maximum CPU time allowed on the salesforce servers is 10,000 milliseconds (for Synchronous calls ) and 60,000 milliseconds(for Asynchronous calls).

To prevent this error, you will need to optimize the code and check for unnecessary loops and where the processis taking longer. The given log does not help much, if you could share the class IntakeClass, we can have a look then.

Cheers,
Dev
Ken Tallman 10Ken Tallman 10
Thank you. The puzzling thing is that this code has worked fine for two years, and in the past two days we’ve gotten this error 3 times. Here's the offending class:

public with sharing class IntakeClass 
{
    /* David Berman, RelationEdge, 16 Dec 2015
     * Checks if new/updated intake records are have an equivalent (dated) intake stat record
     * If necessary, sets up missing daily and monthly intake stat records
     * Calculates:
     *   - average # of residents / day
     *   - average # of residents / month
     *   - average length of stay (in days) by admission date
     */
     
    @future(callout=false)
    public static void processIntakes(Set<ID> setIntakeIDs)
    {
        List<Intake_Stat__c> lstIntakeStats = [SELECT Id, Name, Residents__c, Avg_Length_of_Stay__c, Avg_Residents_per_Day__c, Capacity__c, Date__c, Type__c FROM Intake_Stat__c];
        Map<Id, Intake_Stat__c> mapIntakeStats = new Map<Id, Intake_Stat__c>(lstIntakeStats);

        checkExist(setIntakeIDs, mapIntakeStats);
        setUpIntakeStatDayRecords(mapIntakeStats);
        setUpIntakeStatMonthRecords(mapIntakeStats);

        List<Intake__c> lstIntakes = [SELECT Id, Admission_Date__c, Discharge_Date__c, Resident__c 
            FROM Intake__c WHERE Resident__c != null AND Admission_Date__c != null ORDER BY Admission_Date__c];

        Map<Id, Intake__c> mapIntakes = new Map<Id, Intake__c>(lstIntakes);
        Map<Date, Integer> mapDailyIntakeNumbers = new Map<Date, Integer>();
        Map<Date, Integer> mapLengthOfStayByDate = new Map<Date, Integer>();
        Map<Date, Integer> mapLengthOfStayByDateEntryCounter = new Map<Date, Integer>();
        Map<Date, Integer> mapMonthlySum = new Map<Date, Integer>();
        Map<Date, Integer> mapMonthlyCount = new Map<Date, Integer>();
        Map<Date, Integer> mapMonthCounter = new Map<Date, Integer>();

        // for each intake record loop through start date through end date (or 'today') and update the counts by date
        for(Intake__c intake : lstIntakes)
        {
            Date dLoopDate = intake.Admission_Date__c;    
            Date dEndDate = (intake.Discharge_Date__c != null ? intake.Discharge_Date__c : system.today());

            // Calculate avg duration of stay by admission date
            Integer iLengthOfStayDays = dLoopDate.daysBetween(dEndDate);
            if(!mapLengthOfStayByDate.containsKey(dLoopDate))    
            {
                mapLengthOfStayByDate.put(dLoopDate, iLengthOfStayDays);
            }
            else        
            {
                mapLengthOfStayByDate.put(dLoopDate, mapLengthOfStayByDate.get(dLoopDate) + iLengthOfStayDays);
            }


            if(!mapLengthOfStayByDateEntryCounter.containsKey(dLoopDate))    
            {
                mapLengthOfStayByDateEntryCounter.put(dLoopDate, 1);
            }
            else    
            {
                mapLengthOfStayByDateEntryCounter.put(dLoopDate, mapLengthOfStayByDateEntryCounter.get(dLoopDate) + 1);
            }


            while (dLoopDate <= dEndDate)
            {
                if(mapDailyIntakeNumbers.get(dLoopDate) == null)    
                {
                    mapDailyIntakeNumbers.put(dLoopDate, 1);
                }
                else                                        
                {
                    mapDailyIntakeNumbers.put(dLoopDate, mapDailyIntakeNumbers.get(dLoopDate)+1);
                }
                
                dLoopDate = dLoopDate.addDays(1);
            }
        }

        populateAverages(mapDailyIntakeNumbers, mapLengthOfStayByDate, mapLengthOfStayByDateEntryCounter,
                    mapMonthlySum, mapMonthCounter, mapIntakeStats);
    
    }

/***************************************************************************************************/ 

    private static void populateAverages( 
        Map<Date, Integer> mapDailyIntakeNumbers, 
        Map<Date, Integer> mapLengthOfStayByDate, 
        Map<Date, Integer> mapLengthOfStayByDateEntryCounter,
        Map<Date, Integer> mapMonthlySum, 
        Map<Date, Integer> mapMonthCounter,
        Map<Id, Intake_Stat__c> mapIntakeStats)
    {
//System.debug('+++++ mapIntakeStats size: ' + mapIntakeStats.size());

        for(Intake_Stat__c its : mapIntakeStats.values()) // lstIntakeStats2)
        {
            
            if(its.Type__c == 'Month' && mapMonthlySum.containsKey(its.Date__c))
            {
                Integer daysInMonth = Date.daysInMonth(its.Date__c.year(), its.Date__c.month());
                Date dLastOfMonth2 = Date.NewInstance(its.Date__c.year(), its.Date__c.month()+1, 1);
                dLastOfMonth2 = dLastOfMonth2.addDays(-1);
                
                its.Avg_Residents_per_Day__c = (Double)mapMonthlySum.get(its.Date__c) / daysInMonth;
                its.Avg_Residents_per_Month__c = (Double)mapMonthlySum.get(its.Date__c) / mapMonthCounter.get(dLastOfMonth2);
                
//System.debug('+++++ Avg res (day) (month): ' + its.Date__c + ': ' + mapMonthlySum.get(its.Date__c) + ' :: ' + ' -- avg-d: ' + (Double)mapMonthlySum.get(its.Date__c) / daysInMonth + '; avg-m: ' + (Double)mapMonthlySum.get(its.Date__c) / mapMonthCounter.get(dLastOfMonth2));
            }
            else if(its.Type__c == 'Day' && mapDailyIntakeNumbers.containsKey(its.Date__c))
            {
                Date dLastOfMonth = Date.NewInstance(its.Date__c.year(), its.Date__c.month()+1, 1);
                dLastOfMonth = dLastOfMonth.addDays(-1);
                Date dLastOfPreviousMonth = (Date.NewInstance(its.Date__c.year(), its.Date__c.month()+1, 1).addMonths(-1)).addDays(-1);
                Date Date053112 = Date.NewInstance(2012, 5, 31);
                its.Residents__c = mapDailyIntakeNumbers.get(its.Date__c); // UPDATE TO INTAKE STAT RECORD
                
                if(mapLengthOfStayByDate.containsKey(its.Date__c) && mapLengthOfStayByDateEntryCounter.containsKey(its.Date__c))
                {
                    its.Avg_Length_of_Stay__c = mapLengthOfStayByDate.get(its.Date__c) / 
                    mapLengthOfStayByDateEntryCounter.get(its.Date__c);
                }

                if(mapMonthlySum.get(dLastOfMonth) == null)    
                {
                    mapMonthlySum.put(dLastOfMonth, mapDailyIntakeNumbers.get(its.Date__c));
                }
                else    
                {
                    mapMonthlySum.put(dLastOfMonth, mapMonthlySum.get(dLastOfMonth) + mapDailyIntakeNumbers.get(its.Date__c));
                }
                    
                if(!mapMonthCounter.containsKey(dLastOfMonth))
                {
                    if(dLastOfPreviousMonth == Date053112)    
                    {
                        mapMonthCounter.put(dLastOfMonth, 1);
                    }
                    else    
                    {
                        if(mapMonthCounter.containsKey(dLastOfPreviousMonth))
                        {
                            mapMonthCounter.put(dLastOfMonth, mapMonthCounter.get(dLastOfPreviousMonth) + 1);
                        }
                        else
                        {
                            mapMonthCounter.put(dLastOfMonth, 1);
                        }
                    }
                }    
            }
                    
        }
        try {
            update mapIntakeStats.values();
        } catch(Exception ex) {
            System.debug(System.loggingLevel.ERROR, ex.getMessage());
        }
    }

/***************************************************************************************************/ 

    private static Boolean checkExistByDate(Date dDateToCheck, String strType, Map<Id, Intake_Stat__c> mapIntakeStats)
    {
        Boolean bExists = false;
        if(mapIntakeStats.size() > 0)
        {
            for(Intake_Stat__c its : mapIntakeStats.values())
            {
                if(its.Date__c == dDateToCheck && its.Type__c == strType)
                {
                    bExists = true;
                    break;
                }
            }
        }
        return bExists;
    }

/***************************************************************************************************/ 
    

    private static void checkExist(Set<ID> setIntakeIDs, Map<Id, Intake_Stat__c> mapIntakeStats)
    {
        List<Intake_Stat__c> lstNewDayIntakeStats = new List<Intake_Stat__c>();
        Map<Id, Intake__c> mapIntakes = new Map<Id, Intake__c>([SELECT Id, Admission_Date__c 
            FROM Intake__c 
            WHERE Id =: setIntakeIDs
                AND Admission_Date__c != null]);

        if(mapIntakeStats.size() > 0)
        {
            for(Intake__c it : mapIntakes.values())
            {    
                Boolean addRecord = true;
                for(Intake_Stat__c its : mapIntakeStats.values())
                {
                    if(it.Admission_Date__c == its.Date__c)
                    {
                        addRecord = false;
                        break;
                    }
                }

                if(addRecord)
                {
                    Date dAdmission = it.Admission_Date__c;
                    Integer month = dAdmission.month();
                    Integer year = dAdmission.year();
                    Integer day = dAdmission.day();
                    String sMonth = String.valueOf(month);
                    String sYear = String.valueOf(year);
                    String sDay = String.valueOf(day);
                    
                    Intake_Stat__c newStatDay = new Intake_Stat__c(Name = 'Day : ' + sMonth+'/' + sDay + '/' + sYear,
                            Type__c = 'Day', Date__c = it.Admission_Date__c);
                    
                    lstNewDayIntakeStats.add(newStatDay);
                }
            }

            if(lstNewDayIntakeStats.size() > 0) insert lstNewDayIntakeStats;
        }
        
    }

/***************************************************************************************************/ 

    private static void setUpIntakeStatMonthRecords(Map<Id, Intake_Stat__c> mapIntakeStats)
    {
        List<Intake_Stat__c> lstNewMonthIntakeStats = new List<Intake_Stat__c>();
        Date dLoopDateMonth = Date.newInstance(2012, 5, 1);
        Date dEndDateMonth = system.today();
        Date dLastOfMonth;
        Set<Date> setLastOfMonthDates = new Set<Date>();

        Boolean bAddRecordMonth = true;
        
        while (dLoopDateMonth <= dEndDateMonth)
        {
            dLastOfMonth = Date.NewInstance(dLoopDateMonth.year(), dLoopDateMonth.month()+1, 1);
            dLastOfMonth = dLastOfMonth.addDays(-1);
            
            if(!setLastOfMonthDates.contains(dLastOfMonth) && !checkExistByDate(dLastOfMonth, 'Month', mapIntakeStats))
            {
                setLastOfMonthDates.add(dLastOfMonth);

                Integer month = dLastOfMonth.month();
                Integer year = dLastOfMonth.year();
                Integer day = dLastOfMonth.day();
                String sMonthMonth = String.valueOf(month);
                String sYearMonth = String.valueOf(year);
                String sDayMonth = String.valueOf(day);

                Intake_Stat__c newStatMonth = new Intake_Stat__c(Name = 'Month : ' + sMonthMonth+'/' + sDayMonth + '/' + sYearMonth,
                        Type__c = 'Month', Date__c = dLastOfMonth);
                
                lstNewMonthIntakeStats.add(newStatMonth);
            }
            dLoopDateMonth = dLoopDateMonth.addDays(1);
        }

        if(lstNewMonthIntakeStats.size()>0)    insert lstNewMonthIntakeStats;
    }

/***************************************************************************************************/ 

    //@future
    private static void setUpIntakeStatDayRecords(Map<Id, Intake_Stat__c> mapIntakeStats)
    {
        List<Intake_Stat__c> lstNewIntakeStatsDay = new List<Intake_Stat__c>();
        Date dLoopDate = Date.newInstance(2012, 5, 31);
        Date dToday = system.today();
        Date dLastOfCurrentMonth = Date.NewInstance(dToday.year(), dToday.month()+1, 1);
        dLastOfCurrentMonth = dLastOfCurrentMonth.addDays(-1);
        
        Boolean bAddRecordDay = true;
        
        while (dLoopDate <= dLastOfCurrentMonth)
        {
            if(!checkExistByDate(dLoopDate, 'Day', mapIntakeStats))
            {
                Integer month = dLoopDate.month();
                Integer year = dLoopDate.year();
                Integer day = dLoopDate.day();
                String sMonth = String.valueOf(month);
                String sYear = String.valueOf(year);
                String sDay = String.valueOf(day);
                
                Intake_Stat__c newStatDay = new Intake_Stat__c(Name = 'Day : ' + sMonth+'/' + sDay + '/' + sYear,
                        Type__c = 'Day', Date__c = dLoopDate);
                
                lstNewIntakeStatsDay.add(newStatDay);
            }
            dLoopDate = dLoopDate.addDays(1);
        }
        
        if(lstNewIntakeStatsDay.size()>0)    insert lstNewIntakeStatsDay;
    }
}
Dev_AryaDev_Arya
hi ken,
first of all, if this method was working fine and recently started crashing, then chances are higher that it is happening due to some other code or apex running. Has there been recently added something to Intake_Stat__c, like a trigger or something else? Meanwhile I will keep digging. 

I also looked in to the code and I must say whoever developed the code, knows apex good. I could not figure out any statement which could hinder the proces..

Cheers,
Dev
Dushyant SonwarDushyant Sonwar
Hi Ken ,

Try Changing your class code from below
while (dLoopDate <= dEndDate)
            {
                if(mapDailyIntakeNumbers.get(dLoopDate) == null)    
                {
                    mapDailyIntakeNumbers.put(dLoopDate, 1);
                }
                else                                        
                {
                    mapDailyIntakeNumbers.put(dLoopDate, mapDailyIntakeNumbers.get(dLoopDate)+1);
                }
                
                dLoopDate = dLoopDate.addDays(1);
            }

to
 
if(mapDailyIntakeNumbers.contains(dEndDate)){
				mapDailyIntakeNumbers.put(dEndDate , mapDailyIntakeNumbers.get(dEndDate) + dLoopDate.daysBetween(dEndDate));
			}
			else{
				mapDailyIntakeNumbers.put(dEndDate , dLoopDate.daysBetween(dEndDate));
			}


and change your setUpIntakeStatMonthRecords method to below
 
private static void setUpIntakeStatMonthRecords(Map<Id, Intake_Stat__c> mapIntakeStats){
    
        List<Intake_Stat__c> lstNewMonthIntakeStats = new List<Intake_Stat__c>();
        Date dLoopDateMonth = Date.newInstance(2012, 5, 1);
        Date dEndDateMonth = system.today();
        Date dLastOfMonth;
        Set<Date> setLastOfMonthDates = new Set<Date>();

        Set<String> setOfDates =new Set<String>();
		mapIntakeStats = mapIntakeStats ==null ? new Map<Id, Intake_Stat__c>() : mapIntakeStats;
        for(Intake_Stat__c its : mapIntakeStats.values()){
		
			if(its.Type__c == 'Month'){			
				setOfDates.add(its.Date__c);
			}
		}
        while (dLoopDateMonth <= dEndDateMonth){
        
            dLastOfMonth = Date.NewInstance(dLoopDateMonth.year(), dLoopDateMonth.month()+1, 1);
            dLastOfMonth = dLastOfMonth.addDays(-1);
            
            if(!setLastOfMonthDates.contains(dLastOfMonth) && !setOfDates.contains(dLastOfMonth) ){
            
                setLastOfMonthDates.add(dLastOfMonth);

                Integer month = dLastOfMonth.month();
                Integer year = dLastOfMonth.year();
                Integer day = dLastOfMonth.day();
                String sMonthMonth = String.valueOf(month);
                String sYearMonth = String.valueOf(year);
                String sDayMonth = String.valueOf(day);

                Intake_Stat__c newStatMonth = new Intake_Stat__c(Name = 'Month : ' + sMonthMonth+'/' + sDayMonth + '/' + sYearMonth,
                        Type__c = 'Month', Date__c = dLastOfMonth);
                
                lstNewMonthIntakeStats.add(newStatMonth);
            }
            dLoopDateMonth = dLoopDateMonth.addDays(1);
        }

        if(lstNewMonthIntakeStats.size()>0)    insert lstNewMonthIntakeStats;
    }
Hope this helps.