Asynchronous Apex Patterns

Based on Real Implementation Experience: These patterns come from high-volume integrations, data migrations, and long-running processes where synchronous Apex or Flow is not sufficient.

Overview

Asynchronous Apex APIs—Batch, Queueable, Scheduled, and @future—allow you to:

This document describes when to use each mechanism and how to structure code so that async jobs are testable, observable, and safe.

Prerequisites

When to Use

Use Async Apex When

Avoid Async Apex When

Core Concepts

Transaction Boundaries

Each async job runs in its own transaction with its own governor limits. This allows you to:

Idempotency

Async jobs should be idempotent:

Visibility and Monitoring

Use:

Patterns and Examples

Pattern 1: Queueable for Post-Commit Work

Intent: Perform work that should happen after the main transaction commits (e.g., callouts, notifications).

Structure:

See Queueable Examples for code.

Pattern 2: Batch Apex for Large Data Volumes

Intent: Process hundreds of thousands or millions of records safely.

Structure:

See Batch Examples and apex-batch-template.md.

Pattern 3: Scheduled Apex for Time-Based Jobs

Intent: Run jobs at fixed times (nightly, weekly, hourly).

Structure:

Edge Cases and Limitations

Q&A

Q: When should I choose Batch Apex over Queueable?

A: Use Batch when you need to process very large datasets, need chunking with per-batch context, or want to track progress across many records. Use Queueable for lighter workloads, callouts, and chaining a few jobs where you control the scope.

Q: How many Queueable jobs can I chain?

A: Salesforce enforces limits on concurrent async jobs and job chaining. As a good practice, keep chains short and intentional, and consider Batch or multiple entry points if you need deeper workflows. Always consult the latest governor limits documentation.

Q: How do I test asynchronous Apex?

A: Use Test.startTest() and Test.stopTest() to ensure async jobs run within the test context. Assert on the final state of records, logs, or AsyncApexJob records. For callouts, use Test.setMock() with HttpCalloutMock implementations.