In the Salesforce ecosystem, asynchronous processes are essential tools that allow developers to execute operations in the background, helping overcome platform limitations while creating more responsive user experiences
Before diving into the specifics, let’s understand why asynchronous processing is crucial in Salesforce:

Future methods are the simplest form of asynchronous processing in Salesforce, allowing code execution in a separate thread at a later time.
public class AccountProcessor {
@future
public static void updateAccountRevenue(Set<Id> accountIds) {
List<Account> accountsToUpdate = new List<Account>();
for(Account acc : [SELECT Id, AnnualRevenue FROM Account WHERE Id IN :accountIds]) {
// Perform complex calculation
Double newRevenue = calculateNewRevenue(acc);
acc.AnnualRevenue = newRevenue;
accountsToUpdate.add(acc);
}
if(!accountsToUpdate.isEmpty()) {
update accountsToUpdate;
}
}
private static Double calculateNewRevenue(Account acc) {
// Complex calculation simulation
return acc.AnnualRevenue != null ? acc.AnnualRevenue * 1.1 : 0;
}
}
// Calling the future method
Set<Id> accountIds = new Set<Id>{'001XXXXXXXXXXXXXXX', '001YYYYYYYYYYYYYYY'};
AccountProcessor.updateAccountRevenue(accountIds);
@future annotationBatch Apex allows processing of large record volumes by breaking data into manageable chunks, making it ideal for bulk operations.
public class AccountUpdateBatch implements Database.Batchable<sObject> {
public Database.QueryLocator start(Database.BatchableContext BC) {
// Get all accounts to process
return Database.getQueryLocator('SELECT Id, Name, Description, LastModifiedDate FROM Account WHERE LastModifiedDate = LAST_N_DAYS:30');
}
public void execute(Database.BatchableContext BC, List<Account> scope) {
List<Account> accountsToUpdate = new List<Account>();
for(Account acc : scope) {
acc.Description = 'Updated by batch on ' + System.today();
accountsToUpdate.add(acc);
}
if(!accountsToUpdate.isEmpty()) {
update accountsToUpdate;
}
}
public void finish(Database.BatchableContext BC) {
// Send an email notification when the batch is complete
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {'[email protected]'};
mail.setToAddresses(toAddresses);
mail.setSubject('Account Update Batch Completed');
mail.setPlainTextBody('The batch job to update Account descriptions has completed.');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
// Execute the batch job
Id batchId = Database.executeBatch(new AccountUpdateBatch(), 200);
Queueable Apex combines the flexibility of future methods with the power of batch processing, offering a more modern way to handle asynchronous processing.
public class AccountContactCreator implements Queueable {
private List<Account> accounts;
public AccountContactCreator(List<Account> accounts) {
this.accounts = accounts;
}
public void execute(QueueableContext context) {
List<Contact> contactsToCreate = new List<Contact>();
for(Account acc : accounts) {
// Create a contact for each account
Contact con = new Contact(
AccountId = acc.Id,
LastName = acc.Name + ' Contact',
Email = 'contact@' + acc.Name.toLowerCase().replaceAll(' ', '') + '.com'
);
contactsToCreate.add(con);
}
if(!contactsToCreate.isEmpty()) {
insert contactsToCreate;
// Chain another queueable job
if(!Test.isRunningTest()) {
System.enqueueJob(new AccountOpportunityCreator(accounts));
}
}
}
}
// Class for chained execution
public class AccountOpportunityCreator implements Queueable {
private List<Account> accounts;
public AccountOpportunityCreator(List<Account> accounts) {
this.accounts = accounts;
}
public void execute(QueueableContext context) {
List<Opportunity> oppsToCreate = new List<Opportunity>();
for(Account acc : accounts) {
Opportunity opp = new Opportunity(
AccountId = acc.Id,
Name = acc.Name + ' Opportunity',
StageName = 'Prospecting',
CloseDate = System.today().addDays(30)
);
oppsToCreate.add(opp);
}
if(!oppsToCreate.isEmpty()) {
insert oppsToCreate;
}
}
}
// Execute the queueable job
List<Account> newAccounts = [SELECT Id, Name FROM Account WHERE CreatedDate = TODAY];
Id jobId = System.enqueueJob(new AccountContactCreator(newAccounts));
Scheduled Apex enables running code at specified times using cron expressions, allowing for automation of recurring tasks.
public class DailyAccountSummary implements Schedulable {
public void execute(SchedulableContext ctx) {
// Count accounts created today
Integer newAccounts = [SELECT COUNT() FROM Account WHERE CreatedDate = TODAY];
// Count opportunities closed today
Integer closedOpps = [SELECT COUNT() FROM Opportunity WHERE CloseDate = TODAY AND IsClosed = true];
// Create a summary record
DailySummary__c summary = new DailySummary__c(
Date__c = System.today(),
NewAccounts__c = newAccounts,
ClosedOpportunities__c = closedOpps
);
insert summary;
// You could also call a batch job from here
Database.executeBatch(new AccountUpdateBatch());
}
}
// Schedule the job to run daily at 11:00 PM
String jobName = 'Daily Account Summary';
String cronExp = '0 0 23 * * ?';
System.schedule(jobName, cronExp, new DailyAccountSummary());
Platform Events offer a publish-subscribe model for real-time event-driven architecture, allowing systems to communicate efficiently.
// Define a Platform Event (configuration in Setup)
// OrderEvent__e with fields: Order_Number__c, Status__c, Amount__c
// Publishing a Platform Event
public class OrderProcessor {
public static void publishOrderUpdate(String orderNumber, String status, Decimal amount) {
// Create event instance
OrderEvent__e orderEvent = new OrderEvent__e(
Order_Number__c = orderNumber,
Status__c = status,
Amount__c = amount
);
// Publish event
Database.SaveResult result = EventBus.publish(orderEvent);
// Verify publication
if (!result.isSuccess()) {
for(Database.Error error : result.getErrors()) {
System.debug('Error publishing event: ' + error.getStatusCode() + ' - ' + error.getMessage());
}
}
}
}
// Trigger to subscribe to the event
trigger OrderEventTrigger on OrderEvent__e (after insert) {
List<Order_Notification__c> notifications = new List<Order_Notification__c>();
for (OrderEvent__e event : Trigger.new) {
// Create a record to store the notification
Order_Notification__c notification = new Order_Notification__c(
Order_Number__c = event.Order_Number__c,
Status__c = event.Status__c,
Amount__c = event.Amount__c,
Notification_Date__c = System.now()
);
notifications.add(notification);
}
if (!notifications.isEmpty()) {
insert notifications;
}
}
Change Data Capture provides a way to track and respond to data changes in Salesforce records, enabling real-time integrations.
// Configure CDC in Setup for Account entity
// Apex trigger to handle CDC events
trigger AccountChangeTrigger on AccountChangeEvent (after insert) {
List<CDC_Log__c> logs = new List<CDC_Log__c>();
for (AccountChangeEvent event : Trigger.new) {
// Get all changed fields
EventBus.ChangeEventHeader header = event.ChangeEventHeader;
List<String> changedFields = header.getChangedFields();
// Record the change
CDC_Log__c log = new CDC_Log__c(
Record_ID__c = header.recordIds[0],
Change_Type__c = header.changeType,
Changed_Fields__c = String.join(changedFields, ', '),
Change_Time__c = System.now()
);
// If specific fields changed, take action
if (changedFields.contains('Industry')) {
// Get the new value
String newIndustry = event.Industry;
log.Field_Value__c = newIndustry;
// Additional processing could go here
}
logs.add(log);
}
if (!logs.isEmpty()) {
insert logs;
}
}
| Feature | Future Method | Batch Apex | Queueable Apex | Scheduled Apex | Platform Events | CDC |
|---|---|---|---|---|---|---|
| Complexity | Low | High | Medium | Medium | High | High |
| Record Volume | Low | Very High | Medium | N/A | High | High |
| Status Tracking | No | Yes | Yes | Yes | Partial | Partial |
| Chainable | No | No | Yes | N/A | N/A | N/A |
| Real-time | No | No | No | No | Yes | Yes |
| External System Integration | No | No | No | No | Yes | Yes |
| Complex Parameters | No | Yes | Yes | Yes | Yes | N/A |
| Granular Scheduling | No | No | No | Yes | No | No |
| Error Handling | Poor | Good | Good | Basic | Good | Good |
Asynchronous processing in Salesforce provides powerful solutions to overcome platform limitations and build scalable applications. Each method has its own strengths and appropriate use cases:
[…] Salesforce Async Process – Make the right choice […]