A Beginner’s Guide to Asynchronous Apex: When and How to Use It

A Beginner’s Guide to Asynchronous Apex When and How to Use It Salesforce Shastras

Introduction to Asynchronous Apex

In the world of Salesforce development, Apex is the backbone that supports complex business logic on the platform. However, not all Apex code is created equal. There’s a special breed of Apex known as Asynchronous Apex that is designed to run in the background, providing a powerful way to execute long-running operations without holding up user processes. But what exactly is Asynchronous Apex, and why is it crucial for beginners to understand its use?

Asynchronous Apex allows developers to perform lengthy tasks, such as callouts to external services, processing large data sets, or handling complex logic, in a way that boosts application performance and enhances user experience. By leveraging Asynchronous Apex, you can schedule code to run at a specific time or respond to events, such as updates to records in Salesforce.


Understanding When to Use Asynchronous Apex

Identifying when to utilize Asynchronous Apex is key to harnessing its power effectively. Here are a few scenarios where Asynchronous Apex shines:

  • Batch Processing: When you need to process large numbers of records, such as data cleansing or record updates, batch Apex allows you to process records in batches, thereby reducing the risk of hitting governor limits.
  • Scheduled Operations: If there are tasks that need to run at specific times, like daily or weekly data summaries, scheduled Apex can be deployed to automate these operations.
  • Callouts to External APIs: When your application needs to communicate with external services, future methods can be used to make callouts without affecting the user’s experience negatively.

How to Implement Asynchronous Apex in Your Code

Implementing Asynchronous Apex requires understanding of various constructs available in the Apex language. Here’s a brief overview:

  • Future Methods: Marked with the @future annotation, these methods allow you to perform operations that can run independently and do not need to return a value to the calling code immediately.
  • Sample example:
public class FutureMethodExample {
    @future
    public static void myFutureMethod(List<Id> recordIds) {
        List<Account> accounts = [SELECT Id, Name FROM Account WHERE Id IN :recordIds];
        
        // Perform some operation on the accounts
        for(Account acc : accounts) {
            acc.Name = 'Updated ' + acc.Name;
        }
        
        update accounts;
    }
}

In this example, myFutureMethod is a future method that updates the Name field of Account records. The @future annotation indicates that the method runs asynchronously. When you call a future method, the system adds it to a queue and executes it when system resources become available.

A few things to note about future methods:

  • Future methods must be static methods, and can only return a void type.
  • The specified parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types.
  • Future methods can’t take sObjects or objects as arguments.
  • You can invoke future methods the same way you invoke any other method. However, because future methods are executed asynchronously, they don’t return a value.

Remember to test your future methods with @isTest classes and methods. This ensures that your asynchronous code meets all your requirements when it’s run in a production environment. Here’s an example of a test class for the future method:

@isTest
public class FutureMethodExampleTest {
    @isTest static void testMyFutureMethod() {
        // Create a test account
        Account testAccount = new Account(Name='Test Account');
        insert testAccount;
        
        // Call the future method
        Test.startTest();
        FutureMethodExample.myFutureMethod(new List<Id>{testAccount.Id});
        Test.stopTest();
        
        // After Test.stopTest(), the future method will have been executed
        // Verify the account name was updated
        testAccount = [SELECT Name FROM Account WHERE Id = :testAccount.Id];
        System.assertEquals('Updated Test Account', testAccount.Name);
    }
}

Batch Apex: Ideal for processing large data sets, Batch Apex lets you define a job to split your data into manageable chunks, process each chunk, and then perform any post-processing activities.

Here’s an example of how to use Batch Apex:

public class BatchApexExample implements Database.Batchable<sObject> {
    public String query;

    public BatchApexExample(String q) {
        query = q;
    }

    public Database.QueryLocator start(Database.BatchableContext BC) {
        return Database.getQueryLocator(query);
    }

    public void execute(Database.BatchableContext BC, List<sObject> scope) {
        // process each batch of records
        List<Account> accounts = (List<Account>)scope;
        for(Account a : accounts) {
            a.Name = 'Updated ' + a.Name;
        }
        update accounts;
    }

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

In this example, BatchApexExample is a Batch Apex class that updates the Name field of Account records. The start method is used to collect the records or objects to be processed. The execute method is called for each batch of records. The finish method is used to execute once after all batches are processed.

You can execute the Batch Apex job using the following code:

String query = 'SELECT Id, Name FROM Account';
BatchApexExample b = new BatchApexExample(query);
Database.executeBatch(b);

This will start the Batch Apex job. Salesforce will automatically split the records returned by the query into batches and call the execute method for each batch.

Remember to test your Batch Apex classes with @isTest classes and methods. This ensures that your asynchronous code meets all your requirements when it’s run in a production environment. Here’s an example of a test class for the Batch Apex class:

@isTest
public class BatchApexExampleTest {
    @isTest static void testMyBatchApex() {
        // Create a test account
        Account testAccount = new Account(Name='Test Account');
        insert testAccount;
        
        // Call the Batch Apex job
        Test.startTest();
        String query = 'SELECT Id, Name FROM Account';
        BatchApexExample b = new BatchApexExample(query);
        Database.executeBatch(b);
        Test.stopTest();
        
        // After Test.stopTest(), the Batch Apex job will have been executed
        // Verify the account name was updated
        testAccount = [SELECT Name FROM Account WHERE Id = :testAccount.Id];
        System.assertEquals('Updated Test Account', testAccount.Name);
    }
}

Queueable Apex: This offers more flexibility than future methods, allowing you to chain jobs and hold more complex state across job executions.

Here’s an example of how to use Queueable Apex:

public class QueueableApexExample implements Queueable {
    private List<Id> recordIds;

    public QueueableApexExample(List<Id> recordIds) {
        this.recordIds = recordIds;
    }

    public void execute(QueueableContext context) {
        List<Account> accounts = [SELECT Id, Name FROM Account WHERE Id IN :recordIds];
        
        // Perform some operation on the accounts
        for(Account acc : accounts) {
            acc.Name = 'Updated ' + acc.Name;
        }
        
        update accounts;
    }
}

In this example, QueueableApexExample is a Queueable Apex class that updates the Name field of Account records. The execute method is called when the job is executed.

You can add the job to the queue using the following code:

List<Id> accountIds = new List<Id>{'001xx000003DGQR', '001xx000003DGQS'};
ID jobID = System.enqueueJob(new QueueableApexExample(accountIds));

This will add the Queueable Apex job to the queue. Salesforce will automatically execute the job when system resources become available.

Remember to test your Queueable Apex classes with @isTest classes and methods. This ensures that your asynchronous code meets all your requirements when it’s run in a production environment. Here’s an example of a test class for the Queueable Apex class:

@isTest
public class QueueableApexExampleTest {
    @isTest static void testMyQueueableApex() {
        // Create a test account
        Account testAccount = new Account(Name='Test Account');
        insert testAccount;
        
        // Call the Queueable Apex job
        Test.startTest();
        System.enqueueJob(new QueueableApexExample(new List<Id>{testAccount.Id}));
        Test.stopTest();
        
        // After Test.stopTest(), the Queueable Apex job will have been executed
        // Verify the account name was updated
        testAccount = [SELECT Name FROM Account WHERE Id = :testAccount.Id];
        System.assertEquals('Updated Test Account', testAccount.Name);
    }
}

This test class creates a test Account, adds the Queueable Apex job to the queue, and then verifies that the Account’s Name was updated as expected. The Test.startTest() and Test.stopTest() methods ensure that the Queueable Apex job is executed immediately, rather than being added to the queue. This is necessary for testing asynchronous functionality.


Scheduled Apex: Scheduled Apex in Salesforce allows you to schedule classes to run at specific times. This is useful when you have some tasks that need to be run periodically, like daily or weekly.

  • Here’s an example of how to use Scheduled Apex:
public class ScheduledApexExample implements Schedulable {
    public void execute(SchedulableContext SC) {
        List<Account> accounts = [SELECT Id, Name FROM Account];
        
        // Perform some operation on the accounts
        for(Account acc : accounts) {
            acc.Name = 'Updated ' + acc.Name;
        }
        
        update accounts;
    }
}

In this example, ScheduledApexExample is a Scheduled Apex class that updates the Name field of Account records. The execute method is called when the scheduled job is run.

You can schedule the job using the following code:

String cronExp = '0 0 0 * * ?'; // runs everyday at midnight
String jobName = 'MyScheduledJob';
ScheduledApexExample s = new ScheduledApexExample();
System.schedule(jobName, cronExp, s);

This will schedule the Scheduled Apex job to run every day at midnight. Salesforce will automatically execute the job at the specified time.

Here’s an example of a test class for the Scheduled Apex class:

@isTest
public class ScheduledApexExampleTest {
    @isTest static void testMyScheduledApex() {
        // Create a test account
        Account testAccount = new Account(Name='Test Account');
        insert testAccount;
        
        // Call the Scheduled Apex job
        Test.startTest();
        String cronExp = '0 0 0 * * ?'; // runs everyday at midnight
        String jobName = 'MyScheduledJob';
        ScheduledApexExample s = new ScheduledApexExample();
        System.schedule(jobName, cronExp, s);
        Test.stopTest();
        
        // After Test.stopTest(), the Scheduled Apex job will have been executed
        // Verify the account name was updated
        testAccount = [SELECT Name FROM Account WHERE Id = :testAccount.Id];
        System.assertEquals('Updated Test Account', testAccount.Name);
    }
}

Best Practices for Asynchronous Apex

To ensure your Asynchronous Apex code is efficient, resilient, and maintainable, follow these best practices:

  1. Limit Use of Global Variables: Global variables persist between batch jobs, which can lead to unexpected behavior or governor limit issues.
  2. Use Collections Efficiently: Leverage Apex collections like Lists, Sets, and Maps to process data efficiently and reduce the number of SOQL queries.
  3. Monitor and Optimize Performance: Regularly review the Apex Jobs page in Salesforce to monitor the performance of your Asynchronous Apex jobs and optimize as necessary.

Common Pitfalls and How to Avoid Them

While Asynchronous Apex is powerful, there are pitfalls to watch out for:

  • Hitting Governor Limits: Even though Asynchronous Apex allows for higher governor limits, it’s still possible to hit these limits if not careful.
  • Order of Execution: Jobs might not execute in the order they are queued, which can cause issues if your logic depends on a specific sequence.
  • Error Handling: Implement robust error handling to capture and log issues that arise during asynchronous processing.

Real-World Examples of Asynchronous Apex at Work

Consider a scenario where a company needs to integrate their Salesforce application with an external HR system to synchronize employee records. Using future methods, developers can create a seamless and user-friendly experience where updates in Salesforce trigger callouts to the HR system, updating records without delaying the user’s workflow.

Another example is a retail company that processes thousands of transactions daily. By using Batch Apex, they can efficiently process transactions in off-peak hours, ensuring their application remains performant during peak business hours.


Conclusion and Next Steps

Asynchronous Apex is a powerful tool in the Salesforce developer’s arsenal, enabling the creation of responsive, scalable applications. By understanding when and how to use Asynchronous Apex, you can take your Salesforce development skills to the next level. Practice implementing the different types of Asynchronous Apex in your projects and always adhere to best practices to maximize its benefits.

Ready to dive deeper into Asynchronous Apex? Check out the official Salesforce documentation for more detailed information and advanced techniques. Happy coding!

Leave a Reply

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