Getting Started
Async Lib is a powerful Salesforce Apex framework that provides an elegant solution for managing asynchronous processes. It eliminates common limitations like "Too many queueable jobs" errors and offers a unified API for queueable, batchable, and schedulable jobs.
Why Async Lib?
Salesforce Limits
Apex Context | Queueable | Future | Batch | Schedule |
---|---|---|---|---|
Synchronous or Scheduled* process | 50 | 50 | 100 in Holding status 5 in Queued or Active status | 100 |
Queueable job | 1 | 50 | ||
@future method call | 1 | 0 | ||
Batch job | 1 | 0 | As above in finish() batch method. For start() and execute() methods, the limit is 0. |
Key Benefits
- 🚀 Eliminates Queueable Limits: Automatically handles "Too many queueable jobs" by intelligent chaining and batch overflow
- 🎯 Unified API: Single, consistent interface for all async job types (Queueable, Batchable, Schedulable)
- ⚡ Smart Prioritization: Jobs execute based on priority with automatic sorting
- 🛡️ Advanced Error Handling: Built-in error recovery, rollback options, and continuation strategies
- 📊 Job Tracking: Comprehensive tracking with custom job IDs and result records
- ⚙️ Configuration-Driven: Control job behavior through custom metadata without code changes
- 🔗 Support Finalizers: Execute cleanup logic after job completion with full context
## Core Concepts
### 1. QueueableJob Base Class
All queueable jobs extend the `QueueableJob` abstract class:
```apex
public class MyQueueableJob extends QueueableJob {
public override void work() {
// Your business logic here
System.debug('Processing job: ' + Async.getQueueableJobContext().currentJob.customJobId);
}
}
2. Builder Pattern API
All job types use a fluent builder pattern:
// Queueable Job
Async.queueable(new MyQueueableJob())
.priority(10)
.delay(5)
.enqueue();
// Batch Job
Async.batchable(new MyBatchJob())
.scopeSize(100)
.execute();
// Schedulable Job
Async.schedulable(new MySchedulableJob())
.name('Daily Cleanup')
.cronExpression('0 0 2 * * ? *')
.schedule();
3. Automatic Job Chaining
When queueable limits are reached, Async Lib automatically switches to scheduled-batch-based execution, ensuring your jobs always run without hitting Queueable platform limits.
Your First Queueable Job
Let's create a simple job that processes accounts:
Step 1: Create Your Job Class
public class AccountProcessorJob extends QueueableJob {
private List<Id> accountIds;
public AccountProcessorJob(List<Id> accountIds) {
this.accountIds = accountIds;
}
public override void work() {
// Get job context
Async.QueueableJobContext ctx = Async.getQueueableJobContext();
System.debug('Processing job: ' + ctx.currentJob.customJobId);
// Process accounts
List<Account> accounts = [SELECT Id, Name FROM Account WHERE Id IN :accountIds];
for (Account acc : accounts) {
acc.Description = 'Processed by ' + ctx.currentJob.className;
}
update accounts;
System.debug('Processed ' + accounts.size() + ' accounts');
}
}
Step 2: Enqueue the Job
// Get some account IDs
List<Id> accountIds = new List<Id>{
'0013000000abcdef',
'0013000000ghijkl'
};
// Enqueue the job
Async.AsyncResult result = Async.queueable(new AccountProcessorJob(accountIds))
.priority(5)
.enqueue();
System.debug('Job enqueued with ID: ' + result.customJobId);
Error Handling
Async Lib provides sophisticated error handling options:
Async.queueable(new MyJob())
.continueOnJobEnqueueFail() // Don't fail if enqueue fails
.continueOnJobExecuteFail() // Continue processing other jobs if this fails
.rollbackOnJobExecuteFail() // Rollback any DML if job fails
.enqueue();
Using Finalizers
Finalizers run after job completion and have access to success/failure context:
public class MyJobFinalizer extends QueueableJob.Finalizer {
public override void work() {
Async.QueueableJobContext ctx = Async.getQueueableJobContext();
FinalizerContext finalizerCtx = ctx.finalizerCtx;
if (finalizerCtx.getResult() == ParentJobResult.SUCCESS) {
System.debug('Job completed successfully!');
} else {
System.debug('Job failed: ' + finalizerCtx.getException().getMessage());
}
}
}
// Attach finalizer within a job
public class MyMainJob extends QueueableJob {
public override void work() {
// Do main work...
// Attach finalizer
Async.queueable(new MyJobFinalizer())
.attachFinalizer();
}
}
Configuration
Control job behavior using Custom Metadata (QueueableJobSetting__mdt
):
- Go to Setup → Custom Metadata Types → QueueableJobSetting → Manage Records
- Create or edit settings:
- All: Global settings for all jobs
- Specific Class Name: Settings for specific job classes
Available settings:
- IsDisabled__c: Disable job execution
- CreateResult__c: Create AsyncResult__c records for tracking
What's Next?
Now that you understand the basics:
- Explore the API - Learn about all available methods and options:
- Queueable API - Detailed information on using Queueable jobs
- Batchable API - Detailed information on using Batchable jobs
- Schedulable API - Detailed information on using Schedulable jobs
- Read the Blog Post - Check out the detailed explanation: Apex Queueable Processing Framework
- Initial Scheduled Queueable Batch Job Explanation - Learn why this job is important for framework to function properly.
Quick Tips
- Job Naming: Jobs get unique names with timestamps:
MyJob::2024-01-15T10:30:45.123Z::1
- Custom Job IDs: Every job gets a UUID for tracking independent of Salesforce Job IDs
- Priority Matters: Lower numbers = higher priority. Finalizers always run first.
- Test Friendly: Framework handles test context automatically
- Callouts Supported: Use
QueueableJob.AllowsCallouts
for HTTP callouts