You need to sign in to do that
Don't have an account?
Ken 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
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
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.
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
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;
}
}
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
Try Changing your class code from below
to
and change your setUpIntakeStatMonthRecords method to below
Hope this helps.