What Is Asynchronous Apex and Why Do We Need It?
Asynchronous Apex refers to code that executes in the background, separate from the main processing thread. It is essential for handling resource-intensive, long-running, or bulk operations without impacting user experience or running into Salesforce governor limits. Asynchronous processing lets users perform large data operations, callouts to external services, or schedule jobs for off-peak hours.
Key Reasons to Use Asynchronous Apex:
- Avoids hitting Salesforce governor limits (memory, CPU, DML)
- Improves app performance and responsiveness by delegating work to background processes
- Enables the handling of large data volumes and complex calculations
- Supports processes like scheduled reports, data cleansing, and external API callouts
Types of Asynchronous Apex
| Type | When to Use | Can Chain/Call Each Other? |
|---|---|---|
| Future Method | Simple background tasks, HTTP callouts, sending emails, updates not requiring complex control | Can call another future: No* |
| Batch Apex | Bulk data processing and long-running jobs (thousands/millions of records), bulk data cleansing or migration | Can chain batches: Yes |
| Queueable Apex | Tasks needing complex data types, dependency control, or job chaining | Can chain/call queueable: Yes |
| Schedulable Apex | Automate processes on a schedule (e.g., nightly updates), run batch/queueable jobs periodically | Can start batch/queueable |
*Future methods cannot invoke other future methods directly. Batch, Queueable, and Schedulable can call or chain each other, usually through job submission APIs or by enqueuing jobs.
Explanation of Each Type
Future Method
- What: Runs methods asynchronously using the
@futureannotation. - When to Use: For simple jobs (callouts, email, lightweight updates) that can run in parallel and don’t need complex processing or return values.
- Limitations: Cannot return results or be directly chained, can’t be called from triggers that update related records extensively, not for heavy bulk processing.
Example Use Case: Update an external system after a record changes, send mass emails, or trigger an external API without holding up user actions.
Batch Apex
- What: Divides large record sets into manageable chunks and processes them separately in batches.
- When to Use: For operations involving thousands to millions of records (data migrations, cleansing, recalculations, mass updates).
- Features: Can handle bulk records, manage errors at the record level, and be scheduled/chained.
- Limitations: More setup code required, not for immediate short tasks.
Example Use Case: Standardizing address formats for millions of customer records.
Queueable Apex
- What: Similar to future methods but supports job chaining, complex objects as parameters, and easier monitoring.
- When to Use: When you need to pass more complex data, chain jobs, or handle post-processing tasks. Good for bulk jobs that are smaller than batch jobs but more complex than future jobs.
- Features: Can chain multiple jobs, better monitoring/debugging, supports job dependencies.
Example Use Case: Send email reminders, then update related tasks, then notify users in sequence.
Schedulable Apex
- What: Allows scheduling of Apex code execution based on CRON expressions or preset times.
- When to Use: For jobs needing periodic runs (daily, hourly, custom schedules), like scheduled reporting, regular data cleanup, or recurring integration points.
- Features: Uses the Schedulable interface; can invoke batch or queueable jobs.
Example Use Case: Nightly data integrity checks or monthly data archiving.
Tracking Failing and Successful Records
For bulk asynchronous processes (especially Batch Apex), Salesforce provides ways to count and handle successful and failed records:
- Database.Stateful Interface: Used in Batch Apex to keep running totals of success/failure across different batches.
- Processing Results: Use
Database.SaveResultfor each batch or transaction to check if individual records succeeded (isSuccess()) or failed, and increment counters accordingly. - Error Logging: Failed record IDs and error messages can be logged or emailed for tracking and re-processing if needed.
- AllOrNone Flag: In DML operations, setting
allOrNone = falseallows some records to succeed even if others fail, making it easier to track partial successes.
Sample Mechanism for Success/Failure Counting (Batch Apex)
textpublic class ExampleBatch implements Database.Batchable<SObject>, Database.Stateful {
public Integer successCount = 0;
public Integer failureCount = 0;
public void execute(Database.BatchableContext bc, List<Account> scope) {
Database.SaveResult[] results = Database.update(scope, false);
for(Database.SaveResult res : results) {
if(res.isSuccess()) successCount++;
else failureCount++;
}
}
// Other required methods: start, finish
}
Interview Questions
1. What is Asynchronous Apex? Why use it over synchronous Apex?
Asynchronous Apex enables you to run code in the background, outside of the main execution thread, without blocking user actions. It is essential when performing operations that:
- Take a long time (like bulk updates)
- Must avoid hitting governor limits during synchronous processing
- Should not make users wait for completion
Benefits over synchronous Apex:
- Handles time-consuming operations without making users wait
- Processes large data volumes efficiently by chunking operations
- Provides higher governor limits for some asynchronous processes (like batch jobs)
- Solves mixed DML, callout-from-trigger, and other limitations of synchronous operations
2. Differences: Future, Batch, Queueable, and Schedulable Apex
| Feature | Future Methods | Queueable Apex | Batch Apex | Schedulable Apex |
|---|---|---|---|---|
| Use Case | Simple, quick async tasks | Complex tasks, job chaining | Processing millions of records | Recurring tasks (scheduled jobs) |
| Data Handling | Primitives only | Primitives, Objects, Collections | sObject/Data in chunks | Anything |
| Chaining | Not supported | Supported (one after another) | Can chain with finish() method | Can schedule any class |
| Monitoring | Cannot directly monitor or query | Can monitor with job ID | Full monitoring via AsyncApexJob | Can track scheduled jobs |
| Batch/Parallel | Single context | Runs in separate thread | Data split into manageable batches | Runs as a scheduled job |
| Typical Limits | 50 calls per transaction | Similar to future but more flexible | 50M records per job, 5 concurrent jobs | Similar to Queueable/Future/Batch |
| Example | Send email, callout, logging | Chained data sync, long ops | Lead cleanup, data correction jobs | Nightly cleanup, scheduled reporting |
3. How would you process millions of records in Salesforce?
- Use Batch Apex as it processes large datasets efficiently by dividing data into small, manageable chunks (batches).
- Each batch executes independently, resetting governor limits for every batch.
- Batch jobs can handle up to 50 million records per execution.
- Queueable Apex—while flexible—should be reserved for less massive volumes.
4. Can Future methods call other asynchronous Apex methods?
- No, you cannot call a future method from another future method.
- You cannot directly invoke a future method from Batch Apex or other async contexts either.
- However, a Future method can invoke a Queueable Apex job if you need chaining.
- As of 2025, only certain special orgs with pilot features may support chained futures, but this is rare.
5. How do you track successful and failed records in a Batch Apex job?
- Use the Database class with
allOrNone=false. This returns aDatabase.SaveResult[]for each record. - You can iterate through the results, counting and storing successes and errors.
- Keep a stateful variable to collect errors during execution.
- In the
finish()method, summarize results and, if needed, send notifications or write to a custom log object.
6. When would you prefer Queueable over Future methods?
Prefer Queueable Apex when:
- You need to chain jobs (i.e., run one async job after another)
- You want to pass complex data types (like sObjects or collections)
- Job status tracking and monitoring is important
- You require stateful processing across job executions
Use Future methods only for simple, one-off operations with primitive types where tracking isn’t needed.
7. Describe a scenario for using Scheduled Apex.
Scheduled Apex is perfect for:
- Daily/weekly/monthly data cleanups
- Sending out scheduled reports or notifications
- Performing repeat integrations with external systems at a set time
- Routine maintenance, such as recalculating fields or syncing data between orgs
You implement a class with the Schedulable interface and schedule it via the UI or programmatically with a cron expression.
8. How would you handle partial successes in a batch operation?
Two main methods:
- Use the
Database.method(likeinsert,update) withallOrNone=falseto allow for partial DML success. - Iterate through the returned array of
Database.SaveResult, collecting errors, then log or alert as appropriate. - Use
Database.Statefulto preserve state across batch executions and relay the summary at the end.
9. What are governor limits, and how does asynchronous Apex help address them?
Governor limits are runtime limits enforced by Salesforce to prevent overconsumption of resources (e.g., SOQL queries, DML rows).
- In synchronous Apex, all processing shares a single execution context and its limits.
- Asynchronous Apex (especially Batch and Queueable) increases limits or resets limits per batch/job.
- Example: Batch Apex gets higher limits and a fresh set of governor restrictions for each execution chunk, enabling the processing of far more records safely.
10. How can jobs be chained or scheduled together in Salesforce?
- Queueable Apex allows native chaining: Each queueable job can enqueue another queueable job at completion (single chain depth per job).
- Batch Apex chaining: You can start a new batch from the
finish()method of another. - Schedule recurring jobs: With Schedulable Apex (set with cron expressions), you can automate job execution.
- Job orchestration: Use platform events, Async Apex patterns, or custom logic to sequence jobs as needed for advanced scenarios
11. What happens if a batch job fails midway?
- If a batch Apex job fails during execution, only the current batch is affected—other batches can still proceed.
- Failed records in a batch can be identified using the
Database.SaveResultarray. - Salesforce records errors and marks the job as “Failed” if critical errors occur, and you can view details in the Apex Jobs page.
- To handle failures robustly, implement exception handling and use
Database.Statefulto capture failed records for reporting or possible retry.
12. Can you send notifications after async jobs complete?
- Yes, use the
finish()method in Batch Apex or the end of a Queueable/Schedulable job to send emails, notifications, or platform events upon job completion. - For complex integrations, custom logic can notify users of success, failure, or partial successes.
13. How do you monitor the progress of async jobs?
- Monitor jobs in Setup under “Apex Jobs.”
- For Batch and Queueable Apex, job IDs allow status querying via SOQL on
AsyncApexJobobjects. - Programmatically, you can fetch job status, number of processed/failed batches, and detailed logs.
14. Can governor limits still be reached in async jobs?
- Yes, every batch or async execution gets its own governor limits.
- Limits are generally higher for async compared to synchronous routines, but they are still enforced.
- Example: Each batch execution in Batch Apex gets fresh SOQL and DML limits.
15. How do you use async apex for callouts from triggers?
- Callouts are not allowed directly from triggers because triggers run synchronously.
- Instead, enqueue a Future or Queueable Apex method that performs the callout after the trigger has finished execution.
- Remember: Only one callout per Future method, but Queueable Apex can support multiple callouts.
16. What governor limits apply to each async type?
| Async Type | Per-Execution Limit Examples |
|---|---|
| Future | 50 calls per transaction, 10 callouts, 100 SOQL queries |
| Queueable | 50 jobs added to queue, 50 callouts, 100 SOQL queries |
| Batch Apex | 250,000 records returned in QueryLocator, 50 million records per run, 200 executions per 24 hours, 5 concurrent jobs |
| Schedulable | Follows limits of invoked method |
- Check Salesforce documentation for current and detailed list of limits.
17. How do you debug issues in async jobs?
- Use system debug logs filtered for “Apex Jobs.”
- Log useful information inside try/catch blocks.
- Use email or custom logging to record details on errors or partial successes.
- For persistent issues, chain smaller batches or increase logging levels.
What is the maximum number of async jobs allowed concurrently?
- Salesforce allows up to 5 concurrent batch jobs and up to 50 Queueable jobs added to the queue per transaction.
- The org limit for total number of async jobs in the queue varies by edition and license.
- Exceeding limits results in errors or jobs being delayed.
18. How do you pass parameters to scheduled jobs?
- Implement the
Schedulableinterface with parameters passed in theexecute()method (via custom fields or setup). - Use custom settings, custom objects, or static/class variables to hold state.
- For Queueable and Batch, you can pass objects or record IDs through constructors.
19. How do you implement retry logic for failed records in async jobs?
- Collect failed records in an array within the job.
- After completion, re-process these records using another async job, or set a status for manual intervention.
- For robust retry, schedule another Batch job on failed results via the
finish()method.
20. Which async method is best for large file processing?
- Use Batch Apex for large volumes and file processing, as it can handle millions of records and break processing into manageable chunks.
- For file imports, process in batches through QueryLocator.
- Queueable Apex can supplement for smaller, complex processing tasks.
21. Can Batch/Queueable jobs be aborted or paused once started?
- Yes, jobs can be aborted (terminated) using the “Apex Jobs” page in Setup or via the
System.abortJob(jobId)Apex method. - Pausing is not natively supported; you must design jobs for restart/resume by storing status in custom objects or fields.
Summary Table
| Feature | Use Case Example | Can Chain/Call Others? | Failure/Success Tracking |
|---|---|---|---|
| Future Method | API callouts, mass emails | No | Manual (try/catch) |
| Batch Apex | Data migration, cleansing | Yes | Database.Stateful |
| Queueable Apex | Sequential tasks, complex data | Yes | Custom logic, try/catch |
| Schedulable Apex | Nightly jobs, periodic reports | Yes | N/A (calls others) |
Why Can’t We Call Future Methods From Triggers (in All Cases)?
You can call a future method from a trigger, but with serious restrictions:
- Governor Limit Constraints: When a trigger is run inside another asynchronous process (like Batch or another Future), Salesforce prohibits calling another future method. “Future method cannot be called from a future or batch method” error will occur if you attempt this. This is to prevent abuse and runaway asynchronous chains, which can overload platform resources.
- Typical Scenario: If a trigger is fired during normal user operations, you can call a future method directly from that trigger. However, if the data changes come from a Batch or another asynchronous process, this will fail.
How One Async Option Calls Another (+ Code Examples)
* Subject to not being inside another async context
** Only if not violating async chain limits
1. Calling a Future Method From a Trigger
You can do this if the trigger is not being run from a batch or future context.
texttrigger OpportunityTrigger on Opportunity (after update) {
Set<Id> oppIds = new Set<Id>();
for(Opportunity opp: Trigger.new){
if(opp.StageName == 'Closed Won'){
oppIds.add(opp.Id);
}
}
FutureMethodDemo.sendClosedWonEmail(oppIds);
}
public class FutureMethodDemo {
@future
public static void sendClosedWonEmail(Set<Id> oppIds){
// background process (e.g., send emails)
}
}
Use this pattern only when sure the trigger won’t be invoked by batch/future context.
2. Calling Future From Batch Apex (Not Allowed Directly)
Salesforce prohibits direct call to future methods from batch context. If you try, you’ll see:
“Future method cannot be called from a future or batch method”.
Workaround: Call a Queueable job from the batch, then invoke the future method from the queueable.
textpublic class MyBatch implements Database.Batchable<SObject> {
public Database.QueryLocator start(Database.BatchableContext bc) {
// your query
}
public void execute(Database.BatchableContext bc, List<SObject> scope) {
System.enqueueJob(new MyQueueable(scope));
}
public void finish(Database.BatchableContext bc) { }
}
public class MyQueueable implements Queueable {
List<SObject> records;
public MyQueueable(List<SObject> records) {
this.records = records;
}
public void execute(QueueableContext context) {
FutureClass.process(records); // Now it's allowed
}
}
public class FutureClass {
@future
public static void process(List<SObject> records) {
// Do something asynchronously
}
}
3. Calling Future From Queueable Apex
Permitted if the code is not already triggered by another future method.
textpublic class MyQueueable implements Queueable {
public void execute(QueueableContext context) {
FutureClass.someFutureWork(someId);
}
}
// But you cannot call another queueable from within future, and async chain depth applies[11].
4. Calling Future From Schedulable Apex
Schedulable’s execute() runs in synchronous context, so you can directly call a future method:
textpublic class ScheduledJob implements Schedulable {
public void execute(SchedulableContext sc) {
FutureClass.scheduledTask();
}
}
public class FutureClass {
@future
public static void scheduledTask() {
// background logic
}
}
5. Triggering Other Async Types From Each Other
Future From Future: Not Allowed
text- Chaining future methods (future calling another future) is not supported[7][3].
– Queueable From Future: Possible but With Limits
You’re limited to one Queueable enqueued from any async/future context, else you'll get "Too many queueable jobs..." error[10].
Batch/Queueable/Schedulable can generally invoke Queueable or Batch (within limits).
Key Takeaways
- Don’t call future methods in triggers if the trigger may be invoked as part of batch/future jobs.
- To chain async logic, prefer Queueable Apex or link via supported patterns (Batch→Queueable→Future, etc.)
- Check async chaining and depth limits to avoid system exceptions.
- Use future when you need simple, one-step background logic; use queueable/batch for more complex dependency chains.
Summary Table:
| You Are In… | Can Call Future Directly? | Workaround |
|---|---|---|
| Trigger (normal) | Yes | N/A |
| Batch Apex | No | Batch→Queueable→Future |
| Future Method | No | Use Queueable/Batch |
| Queueable | Yes (limited) | Prefer chaining Queueables |
| Schedulable | Yes | N/A |
Monitoring Asynchronous Apex in Salesforce
Salesforce offers several ways to monitor and manage asynchronous execution, including Future Methods, Batch Apex, Queueable Apex, and Schedulable Apex. Below is an overview of how you can monitor and track each type.
1. General Asynchronous Monitoring
- Apex Jobs Page:
Navigate to Setup → typeJobsin the Quick Find box → select Apex Jobs.- This page lists all asynchronous Apex jobs, including status, submitted time, completion time, and any errors.
- You can filter or search for specific jobs, see job types such as Future, Batch, or Queueable, and drill down for more details.
- Apex Flex Queue:
For Batch Apex jobs waiting to be processed, go to Apex Flex Queue under Jobs in Setup, which allows you to reprioritize pending jobs.
2. Monitoring Future Methods
- Apex Jobs List:
All executed future methods appear here. You can check job status and errors as you would for other jobs. Note that Future Methods do not return a Job ID when invoked. - SOQL Query:
Query theAsyncApexJobobject, filtering by fields such asMethodNameorJobType = 'Future', to track or audit jobs programmatically.
3. Monitoring Batch Apex
- Apex Jobs Page:
Shows all submitted batch jobs, individual batch statuses, processed record count, and error messages per batch. - Batch Jobs Page:
Accessible from a link at the top of the Apex Jobs list, focuses only on batch jobs and allows filtering by date or class. - Apex Flex Queue:
View jobs waiting to run, their order, and reprioritize if needed. - Event Monitoring API:
Leverage for real-time insights and troubleshooting. Advanced admins can use event logs for more granular tracking. - Custom Lightning Components:
For user-friendly monitoring, build custom indicators using LWC and an Apex controller queryingAsyncApexJob.
4. Monitoring Queueable Apex
- Apex Jobs Page:
Every queueable job appears here, with status, job ID, and error details. - Programmatic Monitoring:
TheSystem.enqueueJob()method returns a Job ID, which you can use in a SOQL query onAsyncApexJobfor up-to-date status and error counts:textAsyncApexJob jobInfo = [SELECT Status, NumberOfErrors FROM AsyncApexJob WHERE Id = :jobID]; - Chained Jobs:
Each chained job is listed separately, so monitor each job’s ID in the queue.
5. Monitoring Schedulable Apex
- Scheduled Jobs Page:
In Setup, search for Scheduled Jobs. View all scheduled jobs with information like job name, job type, next scheduled run, and status. - Pause, Resume, or Delete:
You can manage scheduled jobs directly from this UI.
Tips and Best Practices
- Enable Debug Logs:
For detailed execution tracing, set up debug logs for the running user. Helpful for troubleshooting job errors. - Custom Monitoring Objects:
For advanced auditing, log async job results (IDs, status, error messages) in a custom object. - API Monitoring:
Use SOQL and the Event Monitoring API for automated scripts or external dashboards. - Monitor Limits:
Track your org’s asynchronous Apex consumption on the Apex Jobs Setup page to avoid hitting org limits.
Reference Table
| Async Option | Where to Monitor | Extra Tools |
|---|---|---|
| Future Method | Apex Jobs, SOQL on AsyncApexJob | Debug Logs, Custom Logs |
| Batch Apex | Apex Jobs, Batch Jobs, Apex Flex Queue | Event Monitoring API, Custom LWC |
| Queueable Apex | Apex Jobs, SOQL on AsyncApexJob | Chained Job IDs |
| Schedulable Apex | Scheduled Jobs | Apex Jobs (for execution), Pause/Resume/Delete |
Leave a comment