0

I have a scheduled apex class that calls a queueable. This runs daily to retrieve data from an external API, transforms the data, and upserts sObjects. Some of that data transformation relies on Custom Metadata that maps the API value to the Salesforce value (e.g. a status value "1" → "New").

Unfortunately, if I add a new Custom Metadata record, the scheduled job does not see the new Custom Metadata until after I reschedule the job. Why is this happening?

For example, I added a new mapping record to map the API value "9" to Salesforce value "New Status". Manually executing the queueable (i.e. System.enqueueJob()) will result in correct execution with the updated mapping. However, the scheduled job will fail and throw an error because the value "9" isn't mapped. If I simply delete the job and reschedule it, it will run correctly.

2
  • 2
    You might be fetching CMDT data in the schedulable's constructor rather than refetching it in the execute(). Schedulables are serialized upon starting so CMDT data at the time of initial execution is all that is known for subsequent executions. Related Q&A Commented Sep 19 at 17:24
  • @cropredy Thank you. That was it indeed. Commented Sep 21 at 13:26

1 Answer 1

1

As mentioned by @cropredy and their linked answer, this was due to serialization of the schedulable class. Although it's obvious now, it is worth noting that the serialization extends to all code that may be run in the constructor. My class looked something like this:

public class MySchedulable implements Schedulable {

  @TestVisible
  private Orchestrator orchestrator = new Orchestrator();

  public void execute(SchedulableContext context) {
    orchestrator.start();
  }

}

The field map class that referenced the custom metadata is instantiated by a service class that itself is instantiated by the orchestrator and is then executed in the queueable. A simple rewrite will prevent any serialization when running in production, but still allow dependency injection for tests.

public class MySchedulable implements Schedulable {

  @TestVisible
  private Orchestrator orchestrator;

  public void execute(SchedulableContext context) {
    (orchestrator ?? new Orchestrator()).start();
  }

}

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.