Understanding Apex Execution and Limits

Governor Limits and the Multi-Tenant Model

Salesforce enforces strict limits on CPU time, heap size, SOQL queries, and DML operations per transaction to ensure fairness across tenants. Asynchronous operations share these limits differently than synchronous ones, but still operate under specific per-transaction constraints.

Asynchronous Processing in Apex

Batch Apex, Queueables, and Scheduled Apex allow deferred processing outside of synchronous request cycles. However, they introduce new failure modes, including concurrency conflicts and record locking when multiple jobs touch overlapping datasets.

Common Root Causes of Asynchronous Failures

  • Chained Queueables: Excessive chaining without limit checks can trigger unbounded job growth.
  • Batch Scope Size Mismatch: Improperly tuned scope sizes cause frequent retries or partial commits.
  • Lock Contention: Overlapping record updates from concurrent jobs lead to UNABLE_TO_LOCK_ROW errors.
  • Platform Events Backlog: Slow subscribers can cause event delivery delays, impacting dependent processes.

Diagnostics

Step 1: Review Apex Jobs and Debug Logs

Use the Apex Jobs page and Developer Console logs to inspect execution order, limits consumption, and any unhandled exceptions.

System.debug('Remaining CPU Time: ' + Limits.getCpuTime());
System.debug('Remaining Heap Size: ' + Limits.getHeapSize());

Step 2: Monitor Event Bus and Async Queue

Check the Event Monitoring data for Platform Events throughput and AsyncApexJob object for queue backlogs:

SELECT Id, JobType, Status, NumberOfErrors, CreatedDate
FROM AsyncApexJob
WHERE Status IN ('Queued', 'Processing')

Step 3: Trace Record Locks

Enable debug logs for affected users and look for UNABLE_TO_LOCK_ROW errors, which indicate transaction contention.

Architectural Pitfalls

Ignoring Job Concurrency Controls

Without setting Database.Stateful or controlling Database.executeBatch concurrency, jobs may collide on shared data.

Mixing Synchronous and Asynchronous DML Excessively

Complex call chains that span sync and async contexts increase the risk of exceeding aggregate limits.

Step-by-Step Resolution

  1. Implement Guard Clauses: Before enqueuing a job, check AsyncApexJob counts to avoid excessive queues.
  2. Optimize Batch Scope Size: Tune to balance commit frequency with lock contention risk (typical range: 100–200 records).
  3. Use Selective Queries: Reduce dataset size to avoid unnecessary record locking.
  4. Stagger Job Scheduling: Avoid launching overlapping jobs on the same object set.
  5. Leverage Platform Cache: Cache read-heavy data to reduce repeated SOQL/DML in jobs.

Best Practices for Long-Term Stability

  • Design for Idempotency: Ensure jobs can re-run safely without duplicating work.
  • Apply Retry Policies: Use exponential backoff for recoverable errors.
  • Instrument Jobs: Log execution times, limits usage, and error patterns for trend analysis.
  • Partition Data: Distribute work by record ownership or functional segment.
  • Test at Scale: Use Sandbox performance testing to simulate peak load.

Conclusion

Asynchronous Apex is powerful for scaling Salesforce processes, but without careful architectural and operational control, it can become a bottleneck. By understanding execution boundaries, tuning workloads, and implementing concurrency-safe patterns, organizations can achieve reliable high-volume processing while staying within platform limits. Proactive monitoring and disciplined job orchestration are essential to long-term stability.

FAQs

1. How can I prevent Queueable job storms?

Check AsyncApexJob counts before chaining and limit maximum depth. Consider consolidating jobs or using Batch Apex for bulk processing.

2. Why do some async jobs fail without error messages?

They may hit unlogged platform limits or be terminated due to org-wide resource contention. Check debug logs and Event Monitoring data for hidden indicators.

3. How do I detect lock contention patterns?

Correlate UNABLE_TO_LOCK_ROW errors with job start times and target records. Stagger conflicting jobs or partition data.

4. Can I prioritize certain async jobs?

Salesforce does not provide direct priority controls, but you can sequence execution logically by scheduling less critical jobs off-peak.

5. What's the safest way to scale batch jobs?

Gradually increase batch scope sizes in controlled tests while monitoring CPU, heap, and lock error rates. Balance scope for optimal throughput without contention.