How do we write a Batch Class in APEX and schedule it to run?

Scenario

We need to look at all Accounts and update the related Contacts description with Rating field from respective Account. e.g. “Account rating is Cold”

Why Batch Apex ?

Batch Apex is used to process high volume of records and it allows us to run their code on a specific time.

In batch APEX there is the concept of splitting records into Batches to process the records asynchronously, which helps to process the records in multiple threads. Batch APEX has three methods: start, execute and finish.

In this scenario, we will iterate through all the contacts (1 million or more) and update them on a specific date/time.

Batch Class:

global class BatchContactUpdate Implements Database.Batchable<sObject>{
 
 global Database.QueryLocator start(Database.BatchableContext BC){
 string query = 'select Id, Description, Account.Rating from Contact where Account.Rating!=null';
 return Database.getQueryLocator(query);
 }

 global void execute(Database.BatchableContext BC, List<Contact> scope){
 
 List <Contact> contactList = new List <Contact>();
 for (Contact con: scope ){
 
 //Changing the description with Account rating..
 con.Description = 'The Account has ' + con.Account.Rating + 'associated to this contact';
 contactList.add(con);
 }
 if(contactList.size()>0)
 update contactList;
 }
 
 //Finish method can be used for sending an email once batch is completed. 
 global void finish(Database.BatchableContext BC){

 }
}

 

Scheduling an Apex Class

We can schedule the above batch apex to run at a particular time by Using the Scheduler class or Developer console.

Scheduler Class:

To implement a scheduler class,  we will write an Apex class that implements Schedulable interface.

global class SchedulerApex implements Schedulable {

 global void execute(SchedulableContext ctx) {
 BatchContactUpdate bCon = new BatchContactUpdate();
 //Batch size is 200, records will be split into batches 
 Database.ExecuteBatch(bCon,200);
 } 
}

Now you can schedule the batch job by going to:

Setup>Develop>Apex Classes> Click on Schedule Apex and browse  ‘SchedulerApex’ class

Developer Console:

BatchContactUpdate b = new BatchContactUpdate();
DateTime sysTime = System.now();
sysTime = sysTime.addMinutes(2);
String chronJobId = '' + sysTime.second() + ' ' + sysTime.minute() + ' ' + sysTime.hour() + ' ' + sysTime.day() + ' ' + sysTime.month() + ' ? ' + sysTime.year();

//schedule a job
System.schedule('Batch Contact Update Auto'+chronJobId, chronJobId, b);

Chaining of Batch Jobs

We can call one batch job from another job.

For e.g: If we want to process all the tasks related the contacts where the Description are updated, we need to implement a second batch class called “BatchTaskUpdate” which will be called once the previous batch apex “BatchContactUpdate” is completed.

In below code, we execute another batch class in finish method of “BatchContactUpdate”:

global void finish(Database.BatchableContext BC){
  BatchTaskUpdate bTsk = new BatchTaskUpdate();
  Database.ExecuteBatch(bTsk,200);
}

Self Chaining

We can also run/schedule the same batch within the finish method of the batch class. It requires Schedulable interface to be implemented in the same batch class as me

global class BatchContactUpdate Implements Database.Batchable<sObject>, Schedulable {
 
 global Database.QueryLocator start(Database.BatchableContext BC){
 
 }

 global void execute(Database.BatchableContext BC, List<Contact> scope){
 
 }
 
 global void finish(Database.BatchableContext BC){
 
 runJob() ;
 
 }
 
 global void execute(SchedulableContext sc)
 {
  BatchContactUpdate b = new BatchContactUpdate();
  //you can schedule only 5 scheduled bactches can run at a time.
  if ([SELECT count() FROM AsyncApexJob WHERE JobType='BatchApex' AND (Status = 'Processing' OR Status = 'Preparing')] < 5){ 
   Database.executeBatch(b,200); //batch size 200 max
  } else {
   runJob();
  }
 }
 
 public static void runJob(){
  BatchContactUpdate b = new BatchContactUpdate ();
  DateTime sysTime = System.now();
  sysTime = sysTime.addMinutes(2);
  String chronJobId = '' + sysTime.second() + ' ' + sysTime.minute() + ' ' + sysTime.hour() + ' ' + sysTime.day() + ' ' + sysTime.month() + ' ? ' + sysTime.year();
 
  //schedule a job
  System.schedule('Batch Contact Update Auto'+chronJobId, chronJobId, b);
 }
 
}

Additional Resources:

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm

https://developer.salesforce.com/docs/atlas.en-us.apex_workbook.meta/apex_workbook/apex_batch_intro.htm

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm

 
Author:

Ajomon Joseph AJOMON JOSEPH
Senior Salesforce Architect
In Connect me on LinkedIn
twitter Follow me on Twitter @apexcoder
blogger Subscribe to my blog https://apexcoder.com
email Email me ajomon@apexcoder.com

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 )

Google+ photo

You are commenting using your Google+ 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 )

Connecting to %s