Batch Apex

Schedule Batch Apex In Salesforce

In Salesforce, handling large data sets efficiently is crucial to ensure optimal system performance. One powerful tool that helps achieve this is the Batch Apex class.

Batch Apex allows developers to process large volumes of data asynchronously, dividing it into manageable chunks, thereby preventing governor limits from being exceeded.

Schedule Batch Apex In Salesforce

Creating a Schedule Batch Apex

Let's take a look at an example of a Schedulable Batch Apex class that updates the name on Account records at 2AM on the first day of every month.

public class AccountBatchUpdate implements Database.Batchable<sObject>, Schedulable {
    public Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator('SELECT Id, Name FROM Account');
    }

    public void execute(Database.BatchableContext context, List<Account> scope) {
        for (Account acc : scope) {
            // Perform the required data manipulation here
            acc.Name = 'Updated Value';
        }
        update scope;
    }

    public void finish(Database.BatchableContext context) {
        // Perform any post-processing tasks here (optional)
    }
    
    public void execute(SchedulableContext SC) {
        Database.executebatch(new AccountBatchUpdate());
    }
}

The start method is the first method that gets executed when the batch job starts. Its purpose is to return a query locator, which defines the initial set of records that the batch job will process. The query locator is essentially a database query that identifies the records to be operated on during the batch job.

The execute method is the heart of the batch job. It processes the records returned by the start method in smaller batches (default size: 200) and performs the required operations on each batch of records.

The finish method is executed after all batches are processed by the execute method. It provides a way to perform any cleanup or post-processing tasks once the batch job has completed its execution.

Stateful and Stateless Batches:

  1. Stateful batches (using Database.Stateful interface): These batches maintain state across batches, meaning they can retain values of variables between different batches. This allows you to accumulate data or track progress throughout the batch job.

  2. Stateless batches: These batches do not retain state, and variables' values are reset between batches. They are suitable for independent and isolated processing of each batch.

Stateful Batch Example

One common way to maintain data integrity is by using a feature called Database.Stateful and implementing a checkpoint mechanism to handle errors and rollback changes if needed. Here's a code example that demonstrates this concept

public class MyBatchJob implements Database.Batchable<SObject>, Database.Stateful {
    private List<Account> accountsToUpdate;
    private Map<Id, Account> originalAccountsMap;
    
    public Database.QueryLocator start(Database.BatchableContext context) {
        // Query the accounts you want to process
        return Database.getQueryLocator([SELECT Id, Name, Industry FROM Account]);
    }

    public void execute(Database.BatchableContext context, List<Account> scope) {
        // Process each account in the batch
        for (Account account : scope) {
            // Save the original account state for potential rollback
            originalAccountsMap.put(account.Id, account);

            // Perform your updates or data modifications here
            // Example: account.Industry = 'Updated Industry';
            accountsToUpdate.add(account);
        }
    }

    public void finish(Database.BatchableContext context) {
        try {
            // Update the accounts in the database
            update accountsToUpdate;
        } catch (DmlException e) {
            // Handle any exceptions here
            // We will demonstrate a basic rollback by reverting changes
            for (Account account : accountsToUpdate) {
                Account originalAccount = originalAccountsMap.get(account.Id);
                if (originalAccount != null) {
                    // Rollback to the original state
                    account.Industry = originalAccount.Industry;
                }
            }
            System.debug('Error: ' + e.getMessage());
        }
    }
}

In Salesforce Apex, you cannot use Savepoint objects to maintain data integrity in the context of batch processing. Savepoint objects are typically used in the context of triggers or standard transactional processing to create a point of rollback in case of an exception within a single transaction.

In batch Apex, the processing of records is divided into multiple transactions, with each batch of records processed in a separate transaction. Each transaction has its own scope and context, and Savepoint objects are not designed to work across multiple transactions.

How to Schedule a Batch class

Once the batch class is ready, we need to schedule it to run at a specific time. We can do this using the Salesforce user interface, Apex code or using the Developer console on the Execute Anonymous Window. Let's see how to apex schedule batch programmatically:

// Schedule the batch to run at 2 AM on the first day of every month
AccountBatchUpdate accBatch = new AccountBatchUpdate(); 
String sch = '0 0 2 1 * ? *';
String jobID = System.schedule('Change Accounts name', sch, accBatch);

Once the Batch is scheduled you can go to Setup > Scheduled Jobs and the job will be there with the name that you defined above so you can monitor it. From there you can manage your job, see when will be the next execution, change the date/time or remove it.

Test Class for the Batch Apex

To ensure the robustness of the batch class, a test class should be created to cover its execution. Here's an example of a test class for the AccountBatchUpdate:

@isTest
private class TestAccountBatchUpdateTest {
    @isTest
    static void testAccountBatchUpdate() {
        List<Account> testAccounts = new List<Account>();
        for (Integer i = 0; i < 200; i++) {
            testAccounts.add(new Account(Name = 'Test Account ' + i));
        }
        insert testAccounts;

        Test.startTest();
        AccountBatchUpdate batchUpdate = new AccountBatchUpdate();
        Database.executeBatch(batchUpdate);
        Test.stopTest();

        // Perform assertions to validate the updates
        List<Account> updatedAccounts = [SELECT Id, Name FROM Account WHERE Id IN :testAccounts];
        for (Account acc : updatedAccounts) {
            System.assertEquals('Updated Value', acc.Name);
        }
    }
}

Considerations to have

Conclusion

Batch Apex classes are a powerful feature in Salesforce that enables developers to efficiently process large data sets, enhancing overall system performance. By creating Salesforce Schedule Batch class, and following best practices, you can ensure smooth data processing and avoid governor limit issues. Embrace Batch Apex and unlock the true potential of data management in Salesforce.