· tutorials · 4 min read

Mastering Asynchronous Apex in Salesforce: Queueable, Future, Schedulable, and Batch Patterns

Learn how to efficiently integrate and process Salesforce data using Queueable, Future, Schedulable, and Batch Apex patterns.logging, persistent data, and an intuitive dashboard.

Learn how to efficiently integrate and process Salesforce data using Queueable, Future, Schedulable, and Batch Apex patterns.logging, persistent data, and an intuitive dashboard.

As a Salesforce developer, integrating Salesforce data with third-party systems is a frequent task. Clients often require real-time data synchronization when updating records, which typically involves using Apex Triggers. However, attempting to make callouts directly from triggers results in the following error:

"common.apex.runtime.impl.ExecutionException: Callout from triggers are currently not supported."

The solution to this issue is to take our processing out of the current transaction, which can be accomplished using Asynchronous Apex (async Apex). Async Apex refers to several patterns, including:

  • Queueable
  • Future
  • Schedulable
  • Batch

Each of these patterns has its specific use cases and benefits.

Queueable

Queueable classes are one of the most versatile and commonly used interfaces in async Apex. They allow us to break complex problems into smaller, manageable pieces. Here’s how you can leverage Queueable classes:

Creating a Queueable Class

  1. Implement the Queueable Interface: Start with a blank class and implement the Queueable interface. Also, implement the Database.AllowsCallouts interface to enable communication with third-party systems.

  2. Add a Constructor: Add a constructor method to pass context for the smaller problem, usually a list of records to process and a stackSize for debugging.

  3. Define the Execute Method: This method runs when a Queueable job is triggered. It processes the first record from the list and makes the required callout.

Example Code

public class TestQueueable implements Queueable, Database.AllowsCallouts {
    private List<SObject> records;
    private Integer stackSize;

    public TestQueueable(List<SObject> records, Integer stackSize) {
        this.records = records;
        this.stackSize = stackSize;
    }

    public void execute(QueueableContext context) {
        if (!records.isEmpty()) {
            SObject record = records.remove(0);
            // Perform callout with the record
            // Update the record if needed
            System.enqueueJob(new TestQueueable(records, stackSize + 1));
        }
    }
}

Avoiding Limit Errors

Directly enqueuing a Queueable from a trigger can lead to the error:

System.LimitException: Too many queueable jobs added to the queue: 2

To avoid this, check if a job is already enqueued:

if (!System.isEnqueueable()) {
    System.enqueueJob(new TestQueueable(records, 0));
}

Future Methods

Before the introduction of Queueables, future methods were the primary way to handle async Apex. They are still useful in specific scenarios despite their limitations:

  • Cannot use full records
  • Cannot be monitored in the Apex Jobs screen
  • Cannot chain for list processing

Example Use Case

If you need to send an email after a callout and a DML operation, a future method can help avoid callout errors by deferring the email send.

@future
public static void sendEmail(Id contactId) {
    Contact contact = [SELECT Email FROM Contact WHERE Id = :contactId];
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    mail.setToAddresses(new String[] { contact.Email });
    mail.setSubject('Subject');
    mail.setPlainTextBody('Body');
    Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}

Schedulable

For tasks that don’t require real-time processing, you can schedule jobs using the Schedulable interface. This allows you to run background processes at specified intervals using cron expressions.

Example Code

public class ScheduledJob implements Schedulable {
    public void execute(SchedulableContext ctx) {
        // Scheduled processing logic
    }
}

// Scheduling the job
String cronExp = '0 0 0 * * ?'; // Runs every dat at midnight
System.schedule('Daily Job', cronExp, new ScheduledJob());

Batch Apex

Batch Apex is ideal for processing large volumes of data or scheduling hourly callouts. A batch class can be implemented with the Database.Batchable and Database.AllowsCallouts interfaces.

Example Code

public class BatchProcessing implements Database.Batchable<SObject>, Database.AllowsCallouts, Schedulable {
    public Database.QueryLocator start(Database.BatchableContext BC) {
        return Database.getQueryLocator('SELECT Id FROM Account LIMIT 50000');
    }

    public void execute(Database.BatchableContext BC, List<Account> accounts) {
        // Process each account
    }

    public void finish(Database.BatchableContext BC) {
        System.debug('Batch processing complete');
    }

    public void execute(SchedulableContext ctx) {
        Database.executeBatch(new BatchProcessing());
    }
}

// Scheduling the batch job
String cronExp = '0 0 * * * ?'; // Runs every hour
System.schedule('Hourly Batch Job', cronExp, new BatchProcessing());

Summary

Asynchronous Apex is a powerful toolset for Salesforce developers, enabling efficient data processing and integrations. The choice between Queueable, Future, Schedulable, and Batch Apex depends on the specific requirements of your task:

  • Queueable: For breaking down complex problems and chaining jobs.
  • Future: For simple async tasks and avoiding DML callout limits.
  • Schedulable: For scheduled, time-based tasks.
  • Batch: For processing large datasets and making scheduled callouts.

Queueable vs Future vs Batch vs Schedulable

Should you always “just use Queueable”? Not necessarily. While Queueable is versatile, each async pattern has its place in a developer’s toolkit:

  • Schedulable: Time-based scheduling.
  • Queueable: Complex, chainable processing.
  • Future: Simple tasks, avoiding DML callout issues.
  • Batch: Large-scale data processing.

By mastering these async patterns, you can handle a wide range of scenarios in Salesforce, ensuring efficient and effective data processing and integrations. Happy coding!

Need Our Help To Get Your Data Into Salesforce?

Join dozens of other companies by learning how you can get all your company's data in one place.

Back to Blog