I am exeuting Scheduled Apex that should do processing based on the last execution time of the particular code. I query some records for processing and I only want to query those records, that have been changed (SystemModStamp) since the last time the code executed. So I am looking for something lile this:
SELECT ... FROM sObject WHERE SystemModStamp >= :LastExecution
Where LastExecution is automatically calculated during the exceution. If I have code that does not execute within the Cron (say, in Anonymous Apex), this is relatively easy to accomplish:
DateTime LastExecution = DateTime.valueOf([SELECT MAX(PreviousFireTime)LastRun FROM CronTrigger WHERE CronJobDetail.Name LIKE :cronName][0].get('LastRun')
or even easier, if I know the CronTrigger Id:
DateTime LastExecution = [SELECT PreviousFireTime FROM CronTrigger WHERE Id = :arbitraryId].PreviousFireTime
Unfortunately, this pattern does not work if the latter unit is executed from within the scheduled context (thus, retrieving the Trigger id from SchedulableContext.getTriggerId()
). Salesforce updates the CronTrigger record before the code is executed. PreviousFireTime is always the time of execution.
I also tried quering the AsyncApexJob
, but for standard recurring CronTriggers that are scheduled once, there is only one corresponding record in the queue that never gets 'Completed' but always stays 'Queued'. They also do not get re-created, so AsyncApexJob.CreatedDate is identical to CronTrigger.StartTime.
So my question: How do I get the "before" value of PreviousFireTime
?
For relatively easy CronExpressions that define recurring triggers (say 0 0 * * * ?
or 0 0 0 * * ?
) I could calculate the difference between PreviousFireTime
and NextFireTime
and simply substract this difference from PreviousFireTime
to "calculate" an actual previous time. However, this fails for any more complex CronExpressions (say a Job that executes once every hour during business hours (from 8 AM to 8 PM) and if I try to calculate this on the first and last run).
Best Answer
I decided to implement a CronHandler that can be constructed from either a cron id, a scheduled job name or a list of configs that allows me to calculate a Last Execution Time based on a couple of premises.
The API
DateTime getLastExection()
iterates all configs in the handler and returns the latest DateTime value there is. A cron config object can handle the following states:This is enough to:
I would be happy to hear your feedback and suggestions to improve the code.
Here's the class:
And here are some tests: