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...>
lstRecordsToUpdate.add(o);
}
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 = 'giggity@goo.com';
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.

Advertisements

12 thoughts on “Batchable and Schedulable APEX

  1. Great post – thanks a lot! It was hard to find an explanation that included the info about executing anonymous Apex. This got me over the hump.

  2. What’s the best way to debug a hung scheduled batch job? And if you schedule it using Anonymous APEX, the code is just inserted in an execute anonymous window and therefore will be scheduled? Would it then show in the UI under scheduled jobs without the “manage” link? If the code snippet is not entered in execute anonymous, where does it get entered? Thank you in advance!

    • Hey Kyle!

      Hung job: The force.com governors won’t let a job necessarily “hang”, but I have heard of instances where a job gets “stuck” trying to either execute or there is some voodoo that happens when a sandbox is refreshed. If you can’t clear it out, you can grab the ID from the CronTrigger object and do a System.abortJob(Id) against it or call support.

      Scheduled / Anonymous: Typically I’ll take the code that will be executed and create a class – and then schedule that class. Cleaner and easier to manage.

      -Andy

  3. Hi Kyle,

    What’s the jobAutoExtendSchedule do? It’s erroring out on me and I cant quite wrap my head around it. I’ve been exe.anon with my query into a batchable and Id like to convert it and this is my hang spot

  4. Hi sir,
    This is my requirement

    How to run a batch class between Two dates based on frequency(scheduled time) Dynamically from visualforce page?
    In my visualforce page 4 fields
    1)Job name
    2)Startdate(datetime field type)
    3)Enddate(datetime field type)
    4)Frequency(datetime field type)

    My requirement is how to run batch between Startdate and enddate based on Frequency

    Dynamically from visualforce page?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s