Batch Apex Salesforce

Introduction

Batch Apex is used to process large data sets asynchronously by breaking them into manageable chunks.

Key Features

  • Processes up to 50 million records.
  • Uses three methods: start, execute, and finish.

Batch Apex with SObject and Dynamic SOQL

Use Case
To fetch data dynamically using a SOQL query.

Example: Dynamic Query with SObjects

global class BatchWithDynamicQuery implements Database.Batchable<SObject> {
    global Database.QueryLocator start(Database.BatchableContext context) {
        String query = 'SELECT Id, Name FROM Contact WHERE CreatedDate = LAST_N_DAYS:30';
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext context, List<SObject> scope) {
        for (SObject record : scope) {
            Contact con = (Contact)record;
            con.Description = 'Processed in last 30 days';
        }
        update scope;
    }

    global void finish(Database.BatchableContext context) {
        System.debug('Dynamic Query Batch Completed!');
    }
}

Execution

BatchWithDynamicQuery batch = new BatchWithDynamicQuery();
Database.executeBatch(batch, 100); // Process in chunks of 100 records

Batch Apex with Iterable (Database.Iterable)

In Salesforce Batch Apex, you can use an Iterable instead of a query when you need more control over the records or data being processed. The start method can return an object of type Iterable or Iterator to feed data into the batch process.

Why Use an Iterable?

  • You want to process non-SObject data (e.g., custom collections or external API data).
  • You need to create records dynamically without using SOQL.
  • You have a dataset that isn’t directly queryable using SOQL.

Use Case
When processing data not retrieved via SOQL (e.g., custom data structures, strings, or API results).

Batch Class Using Iterable

Syntax

A Batch Apex class using an Iterable looks like this:

global class BatchWithIterableExample implements Database.Batchable<String> {
    
    // Start method returns an Iterable
    global Iterable<String> start(Database.BatchableContext BC) {
        List<String> data = new List<String>{'Record 1', 'Record 2', 'Record 3'};
        return data;
    }

    // Process each chunk of data
    global void execute(Database.BatchableContext BC, List<String> scope) {
        for (String record : scope) {
            System.debug('Processing: ' + record);
        }
    }

    // Finish method for post-processing or notifications
    global void finish(Database.BatchableContext BC) {
        System.debug('Batch Processing Completed!');
    }
}
How to Execute a Batch with Iterable

You can execute the batch as follows:

BatchWithIterableExample batch = new BatchWithIterableExample();
Database.executeBatch(batch, 1); // Process 1 record at a time

When to Use Batch with Iterable

  1. Dynamic Datasets: When the dataset cannot be fetched via SOQL.
  2. Non-SObject Processing: For processing strings, numbers, or any other non-SObject data.
  3. API Integrations: When you need to batch process data fetched from an external system.
  4. Custom Record Construction: For datasets that are dynamically built at runtime.

Batch Apex: Stateful vs Stateless

Stateful Batch Apex

Use Case
Preserve state (variables) across batch transactions.

Key
Implement the Database.Stateful interface.

Example: Stateful Batch

global class StatefulBatchExample implements Database.Batchable<SObject>, Database.Stateful {
    public Integer processedRecords = 0;

    global Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator('SELECT Id, Name FROM Account');
    }

    global void execute(Database.BatchableContext context, List<SObject> scope) {
        for (SObject record : scope) {
            Account acc = (Account)record;
            acc.Name += ' - Processed';
            processedRecords++;
        }
        update scope;
    }

    global void finish(Database.BatchableContext context) {
        System.debug('Total Records Processed: ' + processedRecords);
    }
}

Execution

StatefulBatchExample batch = new StatefulBatchExample();
Database.executeBatch(batch, 200); // Process in chunks of 200 records

Stateless Batch Apex

Use Case
No need to maintain variables or state between executions.

Key
Default behavior (does not implement Database.Stateful).

Example: Stateless Batch

global class StatelessBatchExample implements Database.Batchable<SObject> {
    global Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator('SELECT Id, Name FROM Account');
    }

    global void execute(Database.BatchableContext context, List<SObject> scope) {
        for (SObject record : scope) {
            Account acc = (Account)record;
            acc.Name += ' - Updated';
        }
        update scope;
    }

    global void finish(Database.BatchableContext context) {
        System.debug('Stateless Batch Completed!');
    }
}

Execution

StatelessBatchExample batch = new StatelessBatchExample();
Database.executeBatch(batch, 200); // Process in chunks of 200 records

Batch Apex with API Callouts

Use Case
Perform API callouts during batch processing.

Key

  • Implement Database.AllowsCallouts interface.
  • Perform callouts in the execute method.
Example: Callout in Batch
global class BatchWithCallouts implements Database.Batchable<SObject>, Database.AllowsCallouts {
    global Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator('SELECT Id, Name FROM Account');
    }

    global void execute(Database.BatchableContext context, List<SObject> scope) {
        for (SObject record : scope) {
            Account acc = (Account)record;

            // Example API Callout
            Http http = new Http();
            HttpRequest request = new HttpRequest();
            request.setEndpoint('https://api.example.com/data');
            request.setMethod('GET');
            HttpResponse response = http.send(request);

            if (response.getStatusCode() == 200) {
                acc.Description = 'API Callout Successful';
            }
        }
        update scope;
    }

    global void finish(Database.BatchableContext context) {
        System.debug('Batch with Callouts Completed!');
    }
}

Execution

BatchWithCallouts batch = new BatchWithCallouts();
Database.executeBatch(batch, 50); // Process in chunks of 50 records

Summary of Batch Features:
TypeStateful/StatelessIterable SupportUse Case
Batch with SOQLStatelessNoProcessing large SObject datasets
Batch with IterableStatelessYesCustom non-SObject datasets
Stateful BatchStatefulYesMaintaining variables across transactions
Stateless BatchStatelessYesNo need for state retention
Batch with CalloutsStateless/StatefulYesPerforming API callouts during batch processing

Limitation for Asynchronous

From / WhatCall @future methodSystem.enqueueJob()Database.executeBatch()System.schedule()
Anonymous Apex5050100100
@AuraEnabled method5050100100
@future method010100
Queueable execute()501100100
Schedulable execute()5050100100
Batch start()010100
Batch execute()010100
Batch finish()010100
Platform Event trigger5050100100
Spread the love

Leave a Reply

Your email address will not be published. Required fields are marked *