3

I have a Class that implements the Schedulable interface and the constructor of this class initialises a variable with the value for the current month.

I found out that over the months, the value for this variable hasn't changed, so I was wondering what the order or execution is when it comes to Scheduled Apex.

My guess is that the class is constructed when the Scheduled Job is submitted, and then, every time it runs, it only calls the execute method, but it doesn't invoke the constructor on every run.

Could anyone let me know if I'm right or wrong?

Many thanks, Julio

2 Answers 2

3

Suppose you have a Schedulable class and when it runs, the behavior of the execute() method doesn’t match what you expect. It looks like there’s memory of previous execute()s

Here is a specific example that distills the issue

public class MySchedulable implements Schedulable {

   Account[] accts = new List<Account>();

   public void execute(SchedulableContext sc) {
      accts.addAll([select id, name from Account where YTD_Total__c < 1000.0]);
      // do something interesting with this 
   }

You run the job weekly. You observe on week n, where n > 1, that Accounts are being processed that currently don’t have a YTD_Total__c < 1000. Accounts with YTD_Total__c > 1000 are being processed (?!?)

Explanation

  • When the job is scheduled, the class constructor is called (here, the implicit constructor) and the object variable accts is initialized empty.
  • On week 1, when execute() is called, the accounts with YTD_Total__c < 1000 as of week 1 are added to list accts.
  • On week 2, when execute() is called, the accounts with YTD_Total__c < 1000 as of week 2 are added to list accts.

Note that the class constructor is not reinvoked for each execute(). Hence, the accts list grows and grows. accts is never cleared.

Solution Reinitialize all object variables within the execute().

public class MySchedulable implements Schedulable {

   public void execute(SchedulableContext sc) {
      Account[] accts = new List<Account>();
      accts.addAll([select id, name from Account where YTD_Total__c < 1000.0]);
      // do something interesting with this 
   }
2
  • I just ran into this issue today, when a variable I was using to store logging information kept getting appended to instead of cleared out each run. I know it's been a few years, but thanks for posting your answer to confirm this behavior! Nov 12, 2019 at 23:49
  • @Florissant53 - I remember this well as it vexed me to no end (I originally ran into it in 2013!)
    – cropredy
    Nov 13, 2019 at 1:06
2

We generally use scheduler like this:

schedulerClass m = new schedulerClass();
String sch = '10 20 8 12 1 ?';
String jobID = system.schedule('Job_Name', sch, m);

In this you can see we initiate object of the class earlier (Where the constructor will be called) and we pass only object of scheduler class.

So yes you are right, only execute method will invoke when scheduling time will come.

2
  • But bear in mind that the reality is a bit more complicated as the individual batches can be executed many minutes apart and so the instance is normally flushed from memory. So is the instance serialized to disk and deserialized back into memory (so not invoking the constructor)? If the instance isn't marked with Database.Stateful is it the initial image that is deserialized back into memory every time? In other frameworks a zero arg constructor might me mandatory and invoked per batch. I don't think the documentation is very clear about this.
    – Keith C
    Jun 11, 2015 at 13:53
  • Instance of the class is never flushed when it is scheduled. All information like next time of schedule, previous time etc are also saved. Jun 12, 2015 at 5:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .