Batchable and Schedulable APEX

Keep your friends close, and your Salesforce Governor Limits even closer.

I wholeheartedly agree with Governor Limits in a multi-tenant environment; they are one of the many reasons how Salesforce can keep the level of availability that they do.  They do make you really think on better and more efficient ways to code, that’s for sure.  (All developers in other languages could benefit from a little GL experience IMHO…but I digress)

Along comes a business scenario / requirement that states something to the tune of:

“We need to be able to run a process on a nightly basis to check dates of certain records, and then flip flags based on predetermined threshholds”

Always considering the Declarative before Programmatic Salesforce tenet, you could use something like a time-based workflow rule to fire on the dates.  Absolutely do-able, but let’s just say in this case that we may have historical data or data entered through other means that may not always hit those workflows predictably.  Schedulable and Batchable APEX to the rescue!

Batchable APEX:  The ability to scope records via a SOQL statement, then pass a pre-determined / cursored (in SQL lingo) set of those records through to another APEX class for processing.  Each “batch” is submitted as an entirely separate transaction, thus each batch has its own set of Governor Limits.  In the words of George Takei, “ohhh my!”.

Schedulable APEX:  The ability to specify an APEX class / method to run as a “Scheduled Task” (in windows lingo) or “Cron Job” (*nix lingo) within Salesforce.

Batchable and Schedulable APEX are mutually exclusive; you can have one without the other, but together they are just that much more awesome.

Take our business scenario above – the need to process that data nightly.  Pseudo-coded out, you would:

  1. (optional) Create some APEX that performs your work, preferably either via a trigger or some other method that accepts a List<object> parameter
  2. Create the APEX class that brings in “implements Database.Batchable<SObject>”
  3. Create a final APEX class that brings in “implements Schedulable” to wrap the Batchable class in a nice pretty little package
  4. Submit a Scheduled APEX job to Salesforce
  5. Celebrate by cracking open a nice cold Surly Furious

To show some hardcore examples, here is the code… (forgive the formatting here, my actual code was much prettier!)

Create your APEX “implements Database.Batchable<SObject> class:

global class batchitupson implements Database.Batchable<SObject> {
global String glstrQuery;
global List<SObject> gllstScopeRecords;
// Class Constructor - set query string
global jobAutoExtendSchedule() {
glstrQuery = 'SELECT <whatever> FROM <whatever> WHERE <whichever>';
// "Start" runs when the class in instanciated
global Database.QueryLocator start(Database.BatchableContext bcMain) {
return Database.getQueryLocator(glstrQuery);
// "Execute" is what is being run as a separate process per batch
global void execute(Database.BatchableContext bcMain, List<SObject> lstBatchRecords) {
gllstScopeRecords = lstBatchRecords;
List<your object> lstRecordsToUpdate = new List<your object>();
for(SObject o : gllstScopeRecords) {
<whatever your logic is...>
if(lstRecordsToUpdate.size() > 0) { update lstRecordsToUpdate; }
// Finish the Batch Job
global void finish(Database.BatchableContext bcMain) {
// Optional - you can send an email to an admin with results
String strResultEmail = '';
AsyncApexJob aaJob = [SELECT NumberOfErrors, TotalJobItems FROM AsyncApexJob WHERE Id = :bcMain.getJobId()];
if(aaJob.NumberOfErrors > 0) {
Messaging.SingleEmailMessage semResult = new Messaging.SingleEmailMessage();
semResult.setToAddresses(new String[] {strResultEmail};
semResult.setSubject('Error in Scheduled APEX');
semResult.setPlainTextBody('Processed ' + aaJob.TotalJobItems + ' batches with ' + aaJob.NumberOfErrors + ' failures.');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

Then, wrap it all nicely in a little Schedulable Class…

global class batchitupson_schedule implements Schedulable {
global void execute(SchedulableContext scMain) {
batchitupson clsBatchItUpSon = new batchitupson();
ID idBatch = Database.executeBatch(clsBatchItUpSon, <the number of records per batch>);

And then schedule it to run at 11pm every day via Anonymous APEX:

batchitupson_schedule clsCRON = new batchitupson_schedule();
System.Schedule('Giggity Goo - Scheduleroo', '0 0 23 1-31 1-12 ? *', clsCRON);

Boom goes the dynamite.