4

I have a scheduled Apex class that creates one new record every night with a date field that needs to equal today + three months. I've tried using Date.today().addMonths(3), translating System.now() to a Date format, and trying to grab the date of the most recent record and adding one day to it.

However, the date it references is always the start date of the job, not the current date. Similarly, lastEvent returns the most recent record as of the job start date, not the actual most recent record. This results in every new record created by the scheduled job to have the same date rather than incrementing by one day.

Is this how scheduled jobs are supposed to function? How do I create one record every night with the correct date of today + three months?

global class cc_scheduledVisitEvent implements Schedulable {
    public static String CRON_EXP = '0 0 3 * * ?';

    public Date lastEvent = [SELECT Date__c FROM Visit_Events__c WHERE Date__c != null ORDER BY Date__c DESC LIMIT 1].Date__c;
    public Date eventDate = lastEvent.addDays(1);
    public Date Sunday = eventDate.toStartOfWeek();
    public integer eventDoW = Sunday.daysBetween(eventDate);

    global static String scheduleIt() {
        cc_scheduledVisitEvent ve = new cc_scheduledVisitEvent();
        return System.schedule('Create Visit Event', CRON_EXP, ve);
    }

    global void execute(SchedulableContext ctx) {
        if (eventDate.month() == 5 || eventDate.month() == 6 || eventDate.month() == 7 || eventDate.month() == 8){
            if (eventDoW != 0 || eventDoW != 6){
                Visit_Events__c event = new Visit_Events__c(
                    Name = 'Experience Campus Summer',
                    Date__c = eventDate,
                );
                insert event;
            }
        } else {
            Visit_Events__c event = new Visit_Events__c(
                Name = 'Campus Visit Experience',
                Date__c = eventDate
            );
            insert event;
        }
    }
}
7

When you schedule this class, your instance variables' values are being stored in a "frozen", serialized instance that gets unfrozen to call execute() at the scheduled time. The class-level initialization statements in your code:

public Date lastEvent = [SELECT Date__c FROM Visit_Events__c WHERE Date__c != null ORDER BY Date__c DESC LIMIT 1].Date__c;
public Date eventDate = lastEvent.addDays(1);
public Date Sunday = eventDate.toStartOfWeek();
public integer eventDoW = Sunday.daysBetween(eventDate);

are not run fresh each time execute() is called - the instance variables are retaining their value from the time when the instance was initialized and then frozen. You can address this issue by simply moving the variable declarations to local scope inside the execute() method and removing the access modifiers.

  • 1
    Can you provide a link for this behaviour? Thanks. – Pranay Jaiswal May 2 '18 at 13:38
  • 2
    I'm actually struggling to find explicit documentation on this, Pranay, although it's hinted at in the docs on the transient keyword. – David Reed May 2 '18 at 13:40
  • Yeah.. looks like All schedulable implement database.stateful. yeah.. nice catch. – Pranay Jaiswal May 2 '18 at 13:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.