Blog

There are a lot of declarative automation tools and features introduced by Salesforce in the recent past, which has considerably reduced the need for Apex code. But, to process a large number of records, developers still use the humble Batch Apex.

What is Batch Apex?

Batch Apex is used for processing a large number of records. Since the code is run asynchronously, the records are processed within platform limits. Once the batch Apex job is invoked, the records are processed in batches using the execution logic provided. Each batch is considered a separate Apex transaction.

Batch Apex can handle large data volumes, allows staying within governor limits, and makes it possible to perform a rollback for only the failed batch of records.

Batch Apex is also used to recalculate Apex Managed Sharing. Normal sharing changes to the organization are recalculated automatically. However, Apex sharing changes need to be updated in bulk for all records, which is best done using batch Apex.

A quick look at the general syntax of Batch Apex

global class classname implements Database.Batchable<sObject> {

   global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {
      // collect the batches of records or objects to be passed to execute
   }

   global void execute(Database.BatchableContext bc, List<sObject> records){
      // process each batch of records
   }

   global void finish(Database.BatchableContext bc){
      // execute any post-processing operations
   }
}

A batch Apex class must implement the ‘Database.Batchable’ interface and should include the following methods: start, execute and finish.

Start Method  

  • Defines the scope of the whole process - which records would be considered in the entire batch process
  • Returns either of the two types of objects - Database.QueryLocator or Iterable
  • QueryLocator is the most commonly used object to fetch records without pre-processing, returns up to 50 million records.
  • Iterable is helpful when a lot of initial logic is to be applied to the fetched dataset before actual processing. However, this is governed by the limits on the total number of records that are returned by SOQL queries.

Execute Method   

  • Processes batches of records from the ‘start’ method (sObject records or a list of sObject records), up to 200 records at a time
  • Takes the parameter ‘Database.BatchableContext’ - useful to retrieve information on the batch Apex
  • The second parameter contains the scope returned by ‘Start’ method
  • Has no control over the order of execution of batches

Finish Method   

Post-processing actions - actions that need to be done when all the batches are processed

A real-world scenario to understand Batch Apex processing better

Cityworks is a package delivery company that has delivery stations in multiple states and delivers around 1000 packages every day. The company uses a Salesforce org to manage data about delivery agents and their delivery assignments. Delivery agents are stored in a custom object called ‘Service Agent’. A child object called 'Delivery' is used to store the deliveries assigned to each agent. A secondary Salesforce org is used to manage the delivery assignments of each agent. It exposes a REST-based service that returns new delivery data. At the end of each day, the status of all the new deliveries needs to be updated in the primary Salesforce org.

To meet this requirement, the high-level steps would be:

  1. Connect the external system (secondary Salesforce org) to the primary Salesforce org.
  2. Write a Batch Apex class that executes a callout to the external system to get the required data and update the primary org.
  3. Schedule the Batch Apex class to run every night.

This use case requires the use of batch Apex with some special features and interfaces, namely, Database.Stateful interface, Database.AllowCallouts interface, and Schedulable.

Connecting the external system to the primary Salesforce org

Getting the data from the external system (secondary org)

Since the secondary org provides a REST-based service that returns delivery data, it can be utilized by the primary org to get the required data at the end of each day.

Note: For the sake of convenience and simplicity, the external system in the scenario is a Salesforce org. The following steps show a simple way to connect to a Salesforce org.

Configuring the external system (secondary org)

Connected App:
The first step is to allow the primary org to connect to the secondary org. This can be done by creating a Connected App in the secondary org by navigating to Setup | Apps | App Manager | New Connected App.

Create a New Connected App

The auto-generated consumer key and secret in the connected app can be used in the primary org to connect to the secondary org.

Manage Connected Apps

Configuring the primary org

An ‘Authentication Provider’ and a ‘Named Credential’ can be set up in the primary org to connect to the secondary org. The Authentication Provider should use the consumer key and secret obtained from the connected app.

Set Up an Auth. Provider

Create a Named Credential

The Batch Apex

A Batch Apex class like the following can be created to execute the callout to the secondary org, retrieve the data, and update the records in the primary org.

global class BatchApexCalloutFOF implements Database.Batchable<sObject>, Database.AllowsCallouts, Database.Stateful{

Global List<String> ExternalIDs = new List<String>();
Global Map<String,String> UpdateDeliveryStatus = new map<String,String>();
String a;
String b;
String query;

//Constructor
Global BatchApexCalloutFOF(){
//Callout Logic
Http http = new Http();
HttpRequest request = new HttpRequest();
//Set timeout to 1 minute to avoid read timed out error (only if it appears)
request.setTimeout(60000);
request.setEndpoint('callout:Apex_Rest_Services_Test/services/apexrest/retrieveDeliveries');
request.setMethod('GET');
HttpResponse response = http.send(request);
while (response.getStatusCode() == 302) {
request.setEndpoint(response.getHeader('Location'));
response = new Http().send(request);
}
// If the request is successful, parse the JSON response.
System.debug(response.getBody());
//JSON to get just the external IDs in a list, map to the respective delivery status
JSONParser parser = JSON.createParser(response.getBody());
while (parser.nextToken() != null){
if((parser.getCurrentToken() == JSONToken.FIELD_NAME)){
if (parser.getText() == 'Id')
{
parser.nextToken();
a = parser.getText();
ExternalIDs.add(a);
}
else if (parser.getText() == 'Status__c'){
parser.nextToken();
b = parser.getText();
UpdateDeliveryStatus.put(a,b);
}
}
}
//Verify if the data comes through during runtime
System.debug('JSON External IDs list: ' + ExternalIds);
System.debug('The map:' + UpdateDeliveryStatus);

}

global Database.querylocator start(Database.BatchableContext BC){
system.debug('Inside the Start statement');
//Create query with ExternalIDs list to limit the scope
query = 'Select Id, Name, External_ID__c, Service_Agent__c, Status__c from Delivery__c where External_ID__c in :ExternalIds ';
return Database.getQueryLocator(query);
}



global void execute(Database.BatchableContext BC, List<Delivery__c> scope){
List<Delivery__c> delivs = new List<Delivery__c>();
//Verify the start of the process during runtime
system.debug('Inside the Execute statement');
System.debug('The map:' + UpdateDeliveryStatus);
//Loop through records in scope, batch-wise
for(Delivery__c s : scope){
System.debug('The current record in loop'+ s.External_ID__c);
s.Status__c = UpdateDeliveryStatus.get(s.External_ID__c);
delivs.add(s);
}
update delivs;
}
global void finish(Database.BatchableContext BC){
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses(new String[] {‘admin@fof.com'});
mail.setReplyTo('admin@fof.com');
mail.setSenderDisplayName('Batch Process');
mail.setSubject('Delivery Statuses updated successfully');
mail.setPlainTextBody('Batch Process has completed.');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}

Note: This code does not handle exceptions.

The overall idea behind using the batch Apex code here is to perform a REST callout to the external system to ‘GET’ the data that is required in the form of a JSON response, parse the response, store the external IDs and delivery statuses in variables, retrieve the records to be updated, and then update those records in batches.

Here’s a sample response from the external system:

[
{
"attributes": {
"type": "Delivery__c",
"url": "/services/data/v48.0/sobjects/Delivery__c/a032v00006DbH3oAAF"
},
"Id": "a032v00006DbH3oAAF",
"Name": "D-0000002",
"Service_Agent__c": "a022v00001yJFjzAAG",
"Status__c": "Cancelled"
},
{
"attributes": {
"type": "Delivery__c",
"url": "/services/data/v48.0/sobjects/Delivery__c/a032v00006DbH3jAAF"
},
"Id": "a032v00006DbH3jAAF",
"Name": "D-0000001",
"Service_Agent__c": "a022v00001yJFjzAAG",
"Status__c": "Delivered"
},
{
"attributes": {
"type": "Delivery__c",
"url": "/services/data/v48.0/sobjects/Delivery__c/a032v00006DbH3tAAF"
},
"Id": "a032v00006DbH3tAAF",
"Name": "D-0000003",
"Service_Agent__c": "a022v00001yJFk4AAG",
"Status__c": "Delivered"
}
]

The purpose of the code here is to update only the records for which there is an update from the external system. Since there would be a large set of records already in the system, it is necessary to process only the new deliveries, i.e., around 1000 records per day.

Some important considerations are as follows:

  • Since the code is performing a callout, the interface ‘Database.AllowsCallouts’ needs to be implemented.
  • Before the Start method defines the scope of the process, the callout is made in the constructor method. 
  • As the request is to get the data from the external system, the ‘GET’ http method is used here. The response is in JSON format. 
  • With the response received, the external ids and the respective delivery statuses are collected using JSON Parser methods. This collection of external ids is used in the Start method to return only the records that need to be updated.
  • The list and map defined in the constructor would return null outside the constructor by default, as the batch processing is stateless. To maintain the state (value) of the list and map across different transactions, the class implements the ‘Database.Stateful’ interface.
  • The query is constructed in the start method using the ExternalIds list and returned in the form of a QueryLocator object.
  • The execute method processes the records obtained from the query in batches. The map helps to update the relevant record easily, thereby reducing the number of code lines.
  • The finish method is used to provide an update to the administrator (or any other relevant user) through an email once all batches of records are updated.

Invoking the batch Apex class

For the scenario, the batch Apex class can be scheduled to run at a particular time, especially when no more updates are expected.

The code to run the batch Apex job is placed within another Apex class that implements the ‘schedulable’ interface. This class can be scheduled to run using the Apex Scheduler in Setup.

Code to schedule the batch Apex job:

global class ScheduleDeliveryUpdateFOF implements schedulable
{
   global void execute(SchedulableContext sc)
   {
   BatchApexCalloutFOF quickupdate = new BatchApexCalloutFOF();
   Database.executeBatch(quickupdate,100);
   }
}

Schedule the Batch Apex Class

However, there are other ways to invoke a batch Apex class:

1. A batch Apex class can be invoked using the ‘Database.executeBatch’ method in the Execute Anonymous Apex window in the Developer Console.

BatchApexCallOutFOF quickupdate = new BatchApexCallOutFOF();
Database.executeBatch(quickupdate,100);
//where 100 is limiting the number of records per batch (scope parameter)

Sample Log from Developer Console

2. Batch Apex can be invoked using an Apex trigger. But the trigger should not add more batch jobs than the limit.

How can batch Apex be tested?

The batch Apex class can be tested by simply inserting some sample records in a test class and processing them using the batch class. Only one execution of the ‘execute’ method is possible in a test class. Since Apex test methods don’t support callout to an external system, a mock callout can be created to ‘mock’ the actual callout.

How can batch Apex jobs be monitored?

1. The Apex Jobs page in Setup can be used to monitor batch Apex jobs.

Monitor Batch Apex Job

2. The link to the new batch jobs page can be used.

New Batch Jobs Page

The ‘More Info’ section can be clicked to view detailed information.

More Information on Batch Jobs

3. Batch Apex jobs can also be monitored programmatically. An instance of the ‘Database.BatchableContext’ can be used along with the instance method ‘getJobID’ to retrieve the current batch job Id within the batch class. This can be used in combination with ‘AsyncApexJob’ to obtain additional information about the batch job. Database.executeBatch returns the current job ID when invoking batch Apex.

global void finish(Database.BatchableContext BC){
   AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
      TotalJobItems, CreatedBy.Email
      FROM AsyncApexJob WHERE Id =
      :BC.getJobId()];
      //further finish method logic
}

ID batchprocessid = Database.executeBatch(quickupdate);

AsyncApexJob apexj = [SELECT Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors
   FROM AsyncApexJob WHERE ID =: batchprocessid ];

Chaining Batch Apex Jobs

Batch Apex jobs can be chained together; one job can start another job. This is possible by calling Database.executeBatch or System.scheduleBatch in the finish method of the current batch Apex class. The new batch job will commence after the existing batch job ends. This is handy when dealing with large volumes of data.

Best practices to follow while writing a batch class

  • Use efficient SOQL queries to minimize delay and stay within governor limits.
  • Execute Batch Apex jobs as quickly as possible by minimizing the callout times.
  • Use batch Apex only when there is a need to process more than 200 records at a time (consider the need to process in batches vs. normal Apex code)
  • Consider the number of batches that would stand in a queue if any automation is involved in invoking batch class, such as trigger/process builder process/flow - there can only be five queued or active batch jobs at a time.
  • Define all methods in the class as global or public.
  • Do not call or declare future methods in the batch Apex class.

Happy ‘batching’!

More information on Batch Apex

What Certification are you studying for now?

Focus on Force currently provide practice exams and study guides for nine certifications

Batch Apex in Salesforce

There are a lot of declarative automation tools and features introduced by Salesforce in the recent past, which has considerably reduced the need for Apex code. But, to process a large number of records, developers still use the humble Batch Apex.What is Batch Apex?Batch Apex is used for processing a large number of records. Since the code is run asynchronously, the records are processed within platform limits. Once the batch… Read More

Batch Apex in Salesforce

Focus on People: Mark van Voornveld – Taking the Big Shift: From Microsoft to Salesforce

Mark van Voornveld is an IT professional with a 30-year career built around Microsoft Azure Stack and Dynamics. While relatively new for him, he chose to transition to Salesforce, seeing it as a fresh path to take and a good addition to his expertise. Here, he shared his professional journey, reasons for this transition, and his adjustments to a new CRM and the essential, non-technical skills that make an IT… Read More

Focus on People: Mark van Voornveld – Taking the Big Shift: From Microsoft to Salesforce

Salesforce Einstein: 24/7 At Your Service!

​ Sugar, spice, and ‘everything nice’? Salesforce almost has it all now that Einstein, the smart CRM assistant, is already at our service. Einstein was first introduced as part of the Salesforce Spring ‘17 release and is now a component of Salesforce core cloud products. This innovation was built for the Customer Success Platform to break down the complexity of artificial intelligence technology, helping customers leverage AI capabilities. It must… Read More

Salesforce Einstein: 24/7 At Your Service!

Salesforce: How It Started and How You Can Be Part of the “Ohana”

How did an innovative cloud platform become one of the world’s best CRM solutions?Salesforce has been bringing companies and customers together for over two decades. It began as a Software as a Service (SaaS) company. Salesforce is now the fifth-largest software company in the world. They leverage cloud technology and build a variety of applications for businesses to help better give them key insights into their services through analytics and… Read More

Salesforce: How It Started and How You Can Be Part of the “Ohana”

Apparent Gender Bias Hampers Women’s Career Progression in the Salesforce Ecosystem

by Zoë Morris Flexible and home working are the most desired employment benefits among women working with Salesforce, but their entitlement to these benefits is actually lower than their male counterparts. This is having an adverse effect on gender representation in the Salesforce ecosystem.Mason Frank’s annual salary survey is the largest independent exploration of Salesforce culture. As well as being useful for benchmarking salaries and learning the best education and… Read More

Apparent Gender Bias Hampers Women’s Career Progression in the Salesforce Ecosystem

4 Salesforce Exam Writing Tips to Achieve Salesforce Certification Success

by Cary Walkin Do you have your eye on a Salesforce Certification to advance your career? Perhaps it’s your first certification. Maybe you’re challenging yourself with a difficult certification. I’m a 6x Salesforce Certified professional who has had a career full of exams, and the tips in this guide have helped me and my team pass all of the Salesforce Certification exams that we’ve written. I wrote this guide to… Read More

4 Salesforce Exam Writing Tips to Achieve Salesforce Certification Success

Top 10 Tips for Taking a Salesforce Online Proctored Exam

So you’ve decided to take a Salesforce exam? Congratulations! You’re now one step closer to becoming a Salesforce certified professional. But with the COVID-19 outbreak, taking onsite examinations at a testing center are now not possible.Undergo a safer, more convenient option and take an online proctored exam instead. This is now the perfect time to take these tests especially if you’re worried about the online testing requirements. Because of the… Read More

Top 10 Tips for Taking a Salesforce Online Proctored Exam

Focus on People: Damian Galbally – Maximizing Sales with Salesforce

Damian Galbally became curious about the potential of Salesforce when he was met with some limitations while using it. In this interview, he talked about the challenges he had experienced and how these challenges had shaped the way he helps SMEs maximize Salesforce as a consultant for small businesses today. My name is Damian Galbally, and I am a consultant. My first contact with Salesforce was with a former company I… Read More

Focus on People: Damian Galbally – Maximizing Sales with Salesforce

Get Certified: 91% of Salesforce Professionals Consider Certifications a Factor Impacting Earning Potential

When you work with a technology as fast-moving as Salesforce, it’s incredibly important to read independent research on the ecosystem to ensure you’re steering your career in the right direction.As a Salesforce education provider, it’s really helpful for us to find out where a typical professional struggles in their learning journey and how we can help. Focus on Force was recently featured in the 2019/20 Mason Frank Salary Survey as… Read More

Get Certified: 91% of Salesforce Professionals Consider Certifications a Factor Impacting Earning Potential

Workflow Rules vs Process Builder – When to Use What

Before diving into the differences between Workflow Rules and Process Builders, I do want to call out that in some Trailheads from Salesforce, there have been callouts to moving away from Workflow rules entirely. Be that as it may, Workflows are still up and running and in some cases can be simple, faster, and easier to apply than a Process Builder. However, please do keep this in mind if you… Read More

Workflow Rules vs Process Builder – When to Use What

Focus on People: Jim Vineyard – From Zero to Hero

Jim Vineyard knew nothing about CRM before he explored Salesforce, as part of an account he took on for Customer Service. ​Working with his son in the same company, doing the same job, he navigated through Salesforce and learned a whole new world of custom CRM, and Customer Service functionalities, never before possible for him, in the last decade of his career. I began with Salesforce as a result of the… Read More

Focus on People: Jim Vineyard – From Zero to Hero

Our Top 10 Salesforce Certification Exam Prep Tips

Salesforce is fast becoming the business platform of choice for many companies. With around twenty-seven (27) certifications and counting, you’d know there’s a real – and rather lucrative – career path with Salesforce. It’s true that It takes a lot of work to climb the Salesforce Certification Pyramid, but we all think it’s worth the effort. And If you keep consistent with a system that works for you, you will be… Read More

Our Top 10 Salesforce Certification Exam Prep Tips

Focus on People: Donna Hudson – Never Too Late for Salesforce

Donna chanced upon Salesforce only AFTER RETIRING from her career in higher education. In this interview, she talked about the steps she took to keep up with this all-new, fast-paced tech career as Salesforce Business Analyst. She tells us about her all-women ‘Ohana’ and the benefits of doing non-profit work, to become a better Salesforce professional. I’m not your typical early starter for Salesforce. I’ve been in the work world… Read More

Focus on People: Donna Hudson – Never Too Late for Salesforce

Lightning Replacement to JavaScript Buttons

Prior to the release of Lightning, Javascript buttons got users pretty far with their large variety of use cases. Today, in Lighting, however, Javascript buttons are a thing of the past. Below I am going to walk through several different use cases that, may have been previously handled with Javascript, using one of the Lightning ready ways.Before we begin, here are the Use Cases and the tools in Lightning we… Read More

Lightning Replacement to JavaScript Buttons