Salesforce

Salesforce Apex Asynchronous Process Options: Complete Developer’s Guide (Tech + Use Case Based)

Why Asynchronous Apex is Essential

Modern enterprise applications often require operations that exceed the synchronous limits of Salesforce—like processing large datasets, integrating with third-party APIs, or chaining background jobs. Asynchronous Apex enables background processing without blocking the user or exceeding governor limits.

Benefits include:

  • Handling high-volume record updates
  • Performing long-running HTTP callouts
  • Decoupling user actions from server logic
  • Ensuring scheduled execution of business tasks

Quick Comparison of All Apex Async Types

Async TypeBest ForSupports CalloutsChainingGov Limits (24h)
@futureLightweight fire-and-forget tasks✅ (if callout=true)250k or 200 per license
QueueableComplex logic, chaining, monitoring✅ (1 level)250k
BatchProcessing >50K records in chunksFinish-to-next5 concurrent, 250k daily
ScheduledCRON-based triggers (nightly jobs, etc.)✅ (runs queue/batch)100 concurrent
ContinuationLong-running callouts (VF only)Subject to VF limits
Platform EventsDecoupled, reactive triggersBased on event limits

Future Methods

Use Case: One-off fire-and-forget tasks like logging or sending emails

Example:

apexCopyEdit@future(callout=true)
public static void sendLog(String message) {
    // Post to external system
}

Limitations:

  • No return values
  • No chaining
  • Max 50 future calls per transaction

Queueable Apex

Use Case: Complex logic, supports callouts, better than Future methods

apexCopyEditpublic class AccountSyncJob implements Queueable {
    public void execute(QueueableContext context) {
        // Execute sync logic
    }
}
System.enqueueJob(new AccountSyncJob());

Chaining:

apexCopyEditpublic class FirstJob implements Queueable {
    public void execute(QueueableContext context) {
        System.enqueueJob(new SecondJob());
    }
}

Batch Apex

Use Case: Processing millions of records with high reliability

apexCopyEditglobal class UpdateAccountsBatch implements Database.Batchable<SObject> {
    global Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator('SELECT Id FROM Account');
    }
    global void execute(Database.BatchableContext bc, List<Account> scope) {
        // Update logic here
    }
    global void finish(Database.BatchableContext bc) {
        // Notify or chain next batch
    }
}

Best For:

  • Data cleansing
  • Mass field recalculation
  • Archival processes

Scheduled Apex

Use Case: Time-based triggers (e.g., nightly report generation)

apexCopyEditglobal class DailyTask implements Schedulable {
    global void execute(SchedulableContext ctx) {
        System.enqueueJob(new NightlyQueueJob());
    }
}
apexCopyEditSystem.schedule('Run at midnight', '0 0 0 * * ?', new DailyTask());

Continuation for Long-Running Callouts

Use Case: Visualforce + Long-polling APIs

apexCopyEditpublic Continuation getResults() {
    Continuation cont = new Continuation(60);
    HttpRequest req = new HttpRequest();
    req.setEndpoint('https://slowapi.com/ping');
    cont.addHttpRequest(req);
    return cont;
}

Note: Not usable in LWC or Aura


Platform Events for Reactive Async Processing

Use Case: Decoupled communication across org or external systems

apexCopyEdittrigger EventListener on CustomEvent__e (after insert) {
    for (CustomEvent__e e : Trigger.New) {
        // Trigger async logic
    }
}

Real-World Scenarios and What to Use When

ScenarioBest Async Tool
Sending email notifications@future or Queueable
Sync with external systemQueueable (supports callout + chaining)
Record mass update (>50k)Batch Apex
Daily data exportScheduled + Batch
Cross-module decoupled actionPlatform Events
Visualforce + callout > 5sContinuation

Apex Async Error Handling & Recovery

  • Wrap logic in try/catch blocks
  • Log exceptions to a custom object (Async_Error__c)
  • Use retry flags to prevent loops
  • Alert admins via platform events or custom notification logic

Monitoring Async Jobs in Salesforce

ToolWhat It Shows
Apex Jobs TabStatus, job type, submitted/finished
Developer ConsoleLogs, execution order
WorkbenchQuery AsyncApexJob object
System.enqueueJob()Returns JobId for tracking

Advanced Tips for Chaining & Orchestration

  • Queueable-to-Queueable: Chain in execute()
  • Batch-to-Queueable: Call Queueable in finish()
  • Use custom Async Manager class to track orchestration
apexCopyEditpublic void execute(QueueableContext context) {
    if (condition) {
        System.enqueueJob(new NextStep());
    }
}

Apex Governor Limits for Async Processing

LimitValue
Max Future Calls/Txn50
Max Queueable Jobs/Txn50
Max Batch Jobs Concurrent5
Max Scheduled Apex Jobs100
Total Async Apex Calls/24h250,000 or 200/user license
Max Callouts per Async Txn10

Security Considerations for Async Apex

  • Avoid DML without checking CRUD/FLS
  • Use with sharing to enforce security context
  • Async jobs run in system context by default

Async Apex Design Patterns

  • Fire-and-Forget: Future, basic Queueable
  • Observer Pattern: Platform Events
  • Orchestrator: Queueables with shared context
  • Retry Pattern: Queueables with failure counter logic

FAQs on Salesforce Apex Async

Q: Can I return data from Future or Queueable?
A: No. All async methods are void—use a custom object or Platform Event to persist results.

Q: Can I use async within triggers?
A: Yes, but avoid recursive calls and respect limits.

Q: Best way to monitor chained jobs?
A: Track AsyncApexJob status via JobId returned by System.enqueueJob().


Conclusion

Salesforce offers a rich suite of asynchronous processing tools. Understanding their strengths, limitations, and use cases enables developers to build scalable, resilient, and efficient applications.

Recommendation:

  • Use Queueable for most custom async logic
  • Use Batch for large volumes
  • Use Scheduled for automation
  • Use Platform Events for decoupled triggers
  • Avoid Future, unless extremely lightweight

Leave a Reply