Practical strategies to design scalable asynchronous Apex: bulkify, use Batch Apex, optimize SOQL/DML, and consider event-driven alternatives.
Understanding the challenge
Asynchronous Apex (Future, Queueable, Batch) helps offload long-running work from the user experience, but Salesforce enforces limits on concurrency, daily executions, CPU time and heap size. To build reliable, scalable processes you need to design with these constraints in mind.
Key strategies and best practices
Follow these practical techniques to avoid hitting asynchronous limits and improve performance:
- Bulkify your logic: operate on collections (List, Map, Set) instead of single records and avoid SOQL/DML in loops.
- Limit records per execution: filter queries, use WHERE clauses and process only the records that actually need work.
- Optimize SOQL and DML: select only fields you need, use aggregate queries when appropriate, and perform bulk DML operations.
- Prefer Batch Apex for large volumes: break processing into manageable chunks and control batch size to balance CPU/heap usage.
- Monitor CPU time and heap size: use debug logs and health checks to find hotspots and refactor memory-heavy operations.
- Avoid deep asynchronous chaining: excessive chaining (Future -> Future) quickly consumes concurrency and daily limits.
- Consider event-driven alternatives: Platform Events and Change Data Capture (CDC) offer higher scalability for many event-based workflows.
- Regularly review and refactor: revisit long-running jobs and optimize queries, data structures, and algorithms.
Example: Batch Apex skeleton
public class ExampleBatch implements Database.Batchable{ public Database.QueryLocator start(Database.BatchableContext bc) { return Database.getQueryLocator([SELECT Id FROM Account WHERE LastModifiedDate = LAST_N_DAYS:30]); } public void execute(Database.BatchableContext bc, List scope) { // process records in bulk List updates = new List (); for (sObject s : scope) { Account a = (Account)s; // modify a as needed updates.add(a); } if (!updates.isEmpty()) { update updates; } } public void finish(Database.BatchableContext bc) { // post-processing (notifications, chaining to future safe operations, etc.) } }
Where this matters
These practices benefit Salesforce admins, architects, and developers building integrations, nightly data jobs, mass updates, or event-driven processes. Picking the right asynchronous pattern and tuning batch sizes and queries can prevent production outages and keep user-facing performance smooth.
Quick takeaways
- Design for bulk from day one.
- Use Batch Apex for very large volumes and control chunk sizes.
- Prefer event-driven patterns for scalable, decoupled processing.
- Continuously monitor and refactor resource-heavy jobs.
Why this matters: Salesforce enforces these limits to protect multi-tenant resources — designing with limits in mind results in more reliable apps and happier users across the org.








Leave a Reply