### Common Batchable Example Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/batchable.md This example demonstrates how to create, configure scope size, and execute a common batchable job using the Async API. ```apex Database.Batchable job = new MyBatchJob(); Async.AsyncResult result = Async.batchable(job) .scopeSize(100) .execute(); System.debug('Batch job enqueued: ' + result); ``` -------------------------------- ### Install Async Lib as Unlocked Package Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/introduction/installation.md Use this URL to install the latest version of the Async Lib as an unlocked package directly into your Salesforce org. Note that classes will be prefixed with the 'btcdev' namespace. ```url https://login.salesforce.com/packaging/installPackage.apexp?p0=04tP6000002cgEnIAI ``` -------------------------------- ### Common Schedulable Job Example Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/schedulable.md This example demonstrates how to schedule a common Schedulable job with a name, cron expression, and an option to skip if already scheduled. ```apex Schedulable job = new MySchedulableJob(); List results = Async.schedulable(job) .name('Daily Processing Job') .cronExpression('0 0 2 * * ? *') .skipWhenAlreadyScheduled() .schedule(); System.debug('Scheduled job results: ' + results); ``` -------------------------------- ### Example: Enqueuing 75 Queueable Jobs Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/initial-scheduled-queuable-batch-job.md Demonstrates a real-world scenario where 75 queueable jobs are enqueued. This example shows how Async Lib internally manages the transition from direct queueable enqueuing to using QueueableChainSchedulable for jobs exceeding the limit. ```apex // In your code for (Integer i = 1; i <= 75; i++) { Async.queueable(new ProcessingJob(i)).enqueue(); } ``` -------------------------------- ### Development Setup and Deployment Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/CONTRIBUTING.md Commands to set up a Salesforce scratch org for testing and deploy the project. Includes creating the scratch org and deploying the project. ```bash # Create scratch org for testing sf org create scratch -f config/project-scratch-def.json -a dev sf project deploy start -o dev ``` -------------------------------- ### Deploy Async Lib via Button Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/introduction/installation.md Click this button to deploy the Async Lib to your Salesforce org using the GitHubSFDeploy tool. This is a convenient way to get the library into your org without manual steps. ```html Deploy to Salesforce ``` -------------------------------- ### Initialize QueueableBuilder Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md Constructs a new QueueableBuilder instance with the specified queueable job. This is the starting point for configuring and enqueuing a queueable job. ```apex Async.queueable(new MyQueueableJob()); ``` -------------------------------- ### Build and Enqueue a Queueable Job Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md This example demonstrates how to create a QueueableJob, configure its execution options such as priority and delay, and enqueue it for asynchronous processing. It returns a result object containing the job's unique ID. ```apex QueueableJob job = new MyQueueableJob(); Async.Result result = Async.queueable(job) .priority(5) .delay(2) .continueOnJobExecuteFail() .enqueue(); ``` -------------------------------- ### Mock Queueable Job with Specific ID Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Sets up a mock for a specific queueable job using its mockId. This example demonstrates how to return a predefined `MockQueueableContext` for a job. ```apex @IsTest static void shouldMockQueueableContext() { AsyncMock.whenQueueable('account-creator') .thenReturn(new AsyncMock.MockQueueableContext()); Test.startTest(); Async.queueable(new AccountCreatorJob()) .mockId('account-creator') .enqueue(); Test.stopTest(); } ``` -------------------------------- ### Clone and Deploy Async Lib with SFDX Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/introduction/installation.md Clone the Async Lib repository locally and then deploy it to your Salesforce org using SFDX commands. Ensure you have SFDX CLI installed and configured with your org alias. ```bash git clone https://github.com/beyond-the-cloud-dev/async-lib.git cd async-lib sf project deploy start -p force-app -u your-org-alias ``` -------------------------------- ### Initialize Schedulable Builder Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/schedulable.md Initializes a SchedulableBuilder with a given Schedulable job. This is the starting point for configuring and scheduling a job. ```apex Async.schedulable(new MySchedulableJob()); ``` -------------------------------- ### Soft Clone (Shallow Copy) Example Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/job-cloning.md Demonstrates a soft clone using Apex's standard clone() method, which only copies primitive types and simple collections. Complex objects remain shared by reference. ```apex public class MyJob extends QueueableJob { public String name = 'test'; // ✅ Cloned public Integer count = 5; // ✅ Cloned public Account acc = new Account(); // ❌ Shared reference public List accounts; // ❌ Shared reference } ``` -------------------------------- ### Define a Custom QueueableJob Class Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md This example shows the basic structure of a custom QueueableJob class. You must extend the `QueueableJob` class and implement the `work()` method, which contains the logic to be executed asynchronously. The job context can be retrieved within the `work()` method. ```apex public class AccountProcessorJob extends QueueableJob { public override void work() { // Get job context Async.QueueableJobContext ctx = Async.getQueueableJobContext(); } } ``` -------------------------------- ### Using MockQueueableContext in Apex Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Example of how to instantiate and use MockQueueableContext with a custom queueable job in Apex tests. This allows for direct invocation and testing of queueable logic. ```apex AccountCreatorJob job = new AccountCreatorJob('Direct Test'); job.queueableCtx = new AsyncMock.MockQueueableContext(); job.work(); ``` -------------------------------- ### AccountProcessorJob with Deep Clone Override Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/deep-clone-in-packages.md An example of overriding `cloneForDeepCopy()` in a `QueueableJob` subclass to handle deep cloning of jobs with custom properties like lists and maps. ```apex public class AccountProcessorJob extends btcdev.QueueableJob { public List accounts; public Map config; public override btcdev.QueueableJob cloneForDeepCopy() { return (btcdev.QueueableJob) JSON.deserialize( JSON.serialize(this), AccountProcessorJob.class ); } public override void work() { // process accounts } } ``` -------------------------------- ### Use Meaningful Mock IDs for Targeted Mocking Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/testing-async-jobs.md Provides examples of good and bad practices for naming mock IDs. Using descriptive IDs improves test clarity and maintainability. ```apex // Good AsyncMock.whenFinalizer('payment-error-handler').thenThrow(new PaymentException()); AsyncMock.whenFinalizer('notification-sender').thenReturn(ParentJobResult.SUCCESS); // Avoid generic IDs AsyncMock.whenFinalizer('test').thenThrow(new Exception()); ``` -------------------------------- ### reset Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Clears all mock setups, including both specific mocks configured for particular IDs and any default mocks that have been set. ```APIDOC ## reset ### Description Clears all mock setups (both specific and default mocks). ### Signature ```apex static void reset(); ``` ### Example ```apex AsyncMock.whenFinalizer('test').thenReturn(ParentJobResult.SUCCESS); AsyncMock.whenQueueable('test').thenReturn(new AsyncMock.MockQueueableContext()); AsyncMock.reset(); Assert.isNull(AsyncMock.getFinalizerContext('test')); Assert.isNull(AsyncMock.getQueueableContext('test')); ``` ``` -------------------------------- ### Check for Queueable Mock Existence Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Verifies if a specific or default queueable mock is configured for a given mock ID. Use this to confirm mock setup before retrieval. ```apex AsyncMock.whenQueueable('my-job').thenReturn(new AsyncMock.MockQueueableContext()); Assert.isTrue(AsyncMock.hasQueueableMock('my-job')); Assert.isFalse(AsyncMock.hasQueueableMock('other-job')); ``` -------------------------------- ### Define a Custom Finalizer Class Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md This example illustrates how to create a custom Finalizer class, which extends `QueueableJob.Finalizer`. The `work()` method in this class is executed after the main queueable job completes, allowing for post-processing or cleanup tasks. The finalizer context can be accessed via the job context. ```apex private class ProcessorFinalizer extends QueueableJob.Finalizer { public override void work() { // Get finalizer context FinalizerContext finalizerCtx = Async.getQueueableJobContext().finalizerCtx; } } ``` -------------------------------- ### Get Current Queueable Chain State Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md Gets details about the current Queueable Chain, including jobs and next job IDs. ```APIDOC #### getCurrentQueueableChainState Gets details about the current Queueable Chain. ### Signature ```apex QueueableChainState getCurrentQueueableChainState(); ``` ### Example ```apex QueueableChainState currentChain = Async.getCurrentQueueableChainState(); ``` **Chain state properties:** | Property | Description | |----------|-------------| | `jobs` | All jobs in chain including processed ones and finalizers | | `nextSalesforceJobId` | Salesforce Job Id that will run next (empty if chain not enqueued) | | `nextCustomJobId` | Custom Job Id that will run next from chain | | `enqueueType` | Empty until set during `enqueue()` method | ``` -------------------------------- ### Get Queueable Job Context Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md Gets the current queueable job context, providing access to job information and Salesforce QueueableContext. ```APIDOC ### Context #### getQueueableJobContext Gets the current queueable job context, providing access to job information and Salesforce QueueableContext. ### Signature ```apex Async.QueueableJobContext getQueueableJobContext(); ``` ### Example ```apex Async.QueueableJobContext ctx = Async.getQueueableJobContext(); ``` **Context properties:** | Property | Description | |----------|-------------| | `ctx.currentJob` | Current `QueueableJob` instance | | `ctx.queueableCtx` | Salesforce `QueueableContext` | | `ctx.finalizerCtx` | Salesforce `FinalizerContext` (available in finalizers) | ``` -------------------------------- ### Get Queueable Chain Schedulable ID Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md Gets the ID of the initial Queueable Chain Schedulable if the current execution is part of a scheduled-based chain. ```APIDOC #### getQueueableChainSchedulableId Gets the ID of the initial Queueable Chain Schedulable if the current execution is part of a scheduled-based chain. ### Signature ```apex Id getQueueableChainSchedulableId(); ``` ### Example ```apex Id schedulableId = Async.getQueueableChainSchedulableId(); ``` Returns the Id of the Initial Queueable Chain Schedulable. ``` -------------------------------- ### Get Queueable Chain Schedulable ID Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md Gets the ID of the initial Queueable Chain Schedulable if the current execution is part of a scheduled-based chain. Returns the ID of the Initial Queueable Chain Schedulable. ```apex Id schedulableId = Async.getQueueableChainSchedulableId(); ``` -------------------------------- ### Get Queueable Job Context Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md Gets the current queueable job context, providing access to job information and the Salesforce QueueableContext. This is useful for inspecting the current job's state and parameters. ```apex Async.QueueableJobContext ctx = Async.getQueueableJobContext(); ``` -------------------------------- ### Combine Specific and Default Mocks Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/testing-async-jobs.md Illustrates how to combine specific mock configurations with a default fallback using `AsyncMock.whenFinalizer` and `AsyncMock.whenFinalizerDefault`. Shows how a specific mock is used first, and then the default mock is applied when the specific mock is exhausted. ```apex @IsTest static void shouldFallbackToDefault() { AsyncMock.whenFinalizerDefault().thenReturn(ParentJobResult.SUCCESS); AsyncMock.whenFinalizer('special').thenThrow(new DmlException('Error')); // First call uses specific mock, then falls back to default FinalizerContext ctx1 = AsyncMock.getFinalizerContext('special'); FinalizerContext ctx2 = AsyncMock.getFinalizerContext('special'); Assert.areEqual(ParentJobResult.UNHANDLED_EXCEPTION, ctx1.getResult()); Assert.areEqual(ParentJobResult.SUCCESS, ctx2.getResult()); // Falls back to default } ``` -------------------------------- ### Get Current Queueable Chain State Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md Gets details about the current Queueable Chain, including all jobs in the chain and the next job to be executed. This is useful for understanding the progress and structure of a chained job execution. ```apex QueueableChainState currentChain = Async.getCurrentQueueableChainState(); ``` -------------------------------- ### Clone Async Lib Repository Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/CONTRIBUTING.md Clone your forked repository to your local machine and navigate into the project directory. ```bash git clone https://github.com/YOUR_USERNAME/async-lib.git cd async-lib ``` -------------------------------- ### hasQueueableMock Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Checks if a queueable mock is configured for the given mockId, or if a default mock setup exists that can be used. ```APIDOC ## hasQueueableMock ### Description Checks if a queueable mock exists for the given mockId or if a default mock is configured. ### Signature ```apex static Boolean hasQueueableMock(String mockId); ``` ### Example ```apex AsyncMock.whenQueueable('my-job').thenReturn(new AsyncMock.MockQueueableContext()); Assert.isTrue(AsyncMock.hasQueueableMock('my-job')); Assert.isFalse(AsyncMock.hasQueueableMock('other-job')); ``` ``` -------------------------------- ### Run Project Tests and Checks Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/CONTRIBUTING.md Before committing, run the project's tests and checks to ensure code quality and functionality. This includes LWC Jest tests, ESLint, and Prettier verification. ```bash npm test # Run LWC Jest tests ``` ```bash npm run lint # Run ESLint ``` ```bash npm run prettier:verify # Check code formatting ``` -------------------------------- ### hasFinalizerMock Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Checks if a finalizer mock is configured for the given mockId, or if a default mock setup exists that can be used. ```APIDOC ## hasFinalizerMock ### Description Checks if a finalizer mock exists for the given mockId or if a default mock is configured. ### Signature ```apex static Boolean hasFinalizerMock(String mockId); ``` ### Example ```apex AsyncMock.whenFinalizer('my-job').thenReturn(ParentJobResult.SUCCESS); Assert.isTrue(AsyncMock.hasFinalizerMock('my-job')); Assert.isFalse(AsyncMock.hasFinalizerMock('other-job')); ``` ``` -------------------------------- ### Using deepClone() with Namespaced Package Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/deep-clone-in-packages.md After implementing the `cloneForDeepCopy()` override, you can use the `.deepClone()` method as usual to create a deep copy of your job instance. ```apex btcdev.Async.queueable(new AccountProcessorJob()) .deepClone() .enqueue(); ``` -------------------------------- ### Check for Finalizer Mock Existence Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Verifies if a specific or default finalizer mock is configured for a given mock ID. Useful for asserting mock setup. ```apex AsyncMock.whenFinalizer('my-job').thenReturn(ParentJobResult.SUCCESS); Assert.isTrue(AsyncMock.hasFinalizerMock('my-job')); Assert.isFalse(AsyncMock.hasFinalizerMock('other-job')); ``` -------------------------------- ### Run Apex Tests in Scratch Org Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/CONTRIBUTING.md Command to run Apex tests in the created Salesforce scratch org. ```bash sf apex run test -o dev -l RunLocalTests ``` -------------------------------- ### thenReturn (FinalizerMockSetup) Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Adds a FinalizerContext to the mock queue. Each call to getFinalizerContext consumes one context from the queue (FIFO). ```APIDOC ## thenReturn(FinalizerContext ctx) ### Description Adds a `FinalizerContext` to the mock queue. Each call to `getFinalizerContext` consumes one context from the queue (FIFO). ### Signature ```apex FinalizerMockSetup thenReturn(FinalizerContext ctx); ``` ### Example ```apex AsyncMock.whenFinalizer('multi-test') .thenReturn(new AsyncMock.MockFinalizerContext() .setResult(ParentJobResult.SUCCESS)) .thenReturn(new AsyncMock.MockFinalizerContext() .setResult(ParentJobResult.UNHANDLED_EXCEPTION)); ``` ``` -------------------------------- ### Enqueue, Execute, and Schedule Jobs with Builder Pattern Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/getting-started.md Utilize the fluent builder pattern to configure and execute Queueable, Batchable, and Schedulable jobs. Chain methods to set priority, scope size, schedule details, and more. ```apex // 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 * * ? *') .skipWhenAlreadyScheduled() .schedule(); ``` -------------------------------- ### Async.batchable() Source: https://context7.com/beyond-the-cloud-dev/async-lib/llms.txt Wraps Database.Batchable jobs with a fluent builder. Supports scope size configuration and delayed execution, and can be converted to a schedulable. ```APIDOC ## Async.batchable() ### Description Wraps `Database.Batchable` jobs with a fluent builder. Supports scope size configuration and delayed execution, and can be converted to a schedulable. ### Method `Async.batchable(Database.Batchable batchableInstance)` ### Parameters - **batchableInstance** (Database.Batchable) - Required - The instance of the batchable class to execute. ### Chained Methods - **scopeSize(Integer size)**: Sets the scope size for the batch job. - **minutesFromNow(Integer minutes)**: Sets the delay in minutes before executing the job. - **execute()**: Executes the batch job immediately. - **asSchedulable()**: Converts the batch job configuration to a schedulable job. - **name(String name)**: Sets the name for the schedulable job. - **cronExpression(String cron)**: Sets the cron expression for the schedulable job. - **schedule()**: Schedules the batch job as a schedulable. ### Usage Example ```apex public class AccountCleanupBatch implements Database.Batchable { public Database.QueryLocator start(Database.BatchableContext ctx) { return Database.getQueryLocator([SELECT Id, Description FROM Account WHERE Description = null]); } public void execute(Database.BatchableContext ctx, List scope) { for (Account acc : scope) { acc.Description = 'Cleaned up'; } update scope; } public void finish(Database.BatchableContext ctx) { System.debug('Batch complete: ' + ctx.getJobId()); } } // Execute immediately with scope size 200 Async.Result result = Async.batchable(new AccountCleanupBatch()) .scopeSize(200) .execute(); System.debug('Batch Job ID: ' + result.salesforceJobId); // Execute after a delay Async.batchable(new AccountCleanupBatch()) .scopeSize(100) .minutesFromNow(15) .execute(); // Convert to schedulable for cron-based execution Async.batchable(new AccountCleanupBatch()) .scopeSize(200) .asSchedulable() .name('Nightly Account Cleanup') .cronExpression(new CronBuilder().everyDay(2, 0)) // daily at 2:00 AM .schedule(); ``` ``` -------------------------------- ### Deep Clone (Optional) Usage Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/job-cloning.md Shows how to enable deep cloning in Async Lib using the .deepClone() method. This ensures complete object isolation by serializing and deserializing the job. ```apex Async.queueable(myJob) .deepClone() // Enable deep cloning .enqueue(); ``` -------------------------------- ### MockQueueableContext Class Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md The MockQueueableContext class implements the System.QueueableContext interface, allowing you to simulate the context of a queueable job during tests. It provides methods to set and get the job ID. ```APIDOC ## MockQueueableContext Implements `System.QueueableContext` for test scenarios. ### Class Signature ```apex public class MockQueueableContext implements System.QueueableContext ``` ### Build Methods | Method | Description | |---------------------|--------------------| | `setJobId(Id jobId)` | Sets the job ID | ### Interface Methods | Method | Description | |----------------|-----------------------------| | `getJobId()` | Returns the configured job ID | ### Example Usage ```apex AccountCreatorJob job = new AccountCreatorJob('Direct Test'); job.queueableCtx = new AsyncMock.MockQueueableContext(); job.work(); ``` ``` -------------------------------- ### getQueueableContext Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Retrieves and removes the next QueueableContext from the mock queue for the specified mockId. If the specific mock queue is exhausted, it falls back to using the default mock setup. ```APIDOC ## getQueueableContext ### Description Retrieves and removes the next `QueueableContext` from the mock queue. Falls back to default mock if specific mock is exhausted. ### Signature ```apex static QueueableContext getQueueableContext(String mockId); ``` ### Example ```apex AsyncMock.whenQueueableDefault().thenReturn(new AsyncMock.MockQueueableContext()); AsyncMock.whenQueueable('special').thenReturn(new AsyncMock.MockQueueableContext()); QueueableContext ctx1 = AsyncMock.getQueueableContext('special'); QueueableContext ctx2 = AsyncMock.getQueueableContext('special'); Assert.isNotNull(ctx1); Assert.isNotNull(ctx2); // Falls back to default ``` ``` -------------------------------- ### getFinalizerContext Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Retrieves and removes the next FinalizerContext from the mock queue for the specified mockId. If the specific mock queue is exhausted, it falls back to using the default mock setup. ```APIDOC ## getFinalizerContext ### Description Retrieves and removes the next `FinalizerContext` from the mock queue. Falls back to default mock if specific mock is exhausted. ### Signature ```apex static FinalizerContext getFinalizerContext(String mockId); ``` ### Example ```apex AsyncMock.whenFinalizerDefault().thenReturn(ParentJobResult.SUCCESS); AsyncMock.whenFinalizer('special').thenThrow(new DmlException('Error')); FinalizerContext ctx1 = AsyncMock.getFinalizerContext('special'); FinalizerContext ctx2 = AsyncMock.getFinalizerContext('special'); Assert.areEqual(ParentJobResult.UNHANDLED_EXCEPTION, ctx1.getResult()); Assert.areEqual(ParentJobResult.SUCCESS, ctx2.getResult()); // Falls back to default ``` ``` -------------------------------- ### Traditional Apex Async Job Test Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/testing-async-jobs.md Demonstrates the traditional approach to testing async jobs using Test.startTest() and Test.stopTest(). This method has limitations in controlling context and simulating errors. ```apex ```apex @IsTest static void traditionalTest() { Test.startTest(); Async.queueable(new MyJob()).enqueue(); Test.stopTest(); // Can only verify end results, not intermediate states // Cannot test error handling paths // Cannot test finalizer behavior with exceptions } ``` ``` -------------------------------- ### Create and Enqueue an Account Processor Job Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/getting-started.md Implement a Queueable job to process a list of Account records. The job retrieves accounts by ID, updates their Description field, and logs the processing details. ```apex public class AccountProcessorJob extends QueueableJob { private List accountIds; public AccountProcessorJob(List 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 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'); } } ``` ```apex // Get some account IDs List accountIds = new List{ '0013000000abcdef', '0013000000ghijkl' }; // Enqueue the job Async.Result result = Async.queueable(new AccountProcessorJob(accountIds)) .priority(5) .enqueue(); System.debug('Job enqueued with ID: ' + result.customJobId); ``` -------------------------------- ### Get Complete Cron Expression String Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/schedulable.md Use `getCronExpression` to retrieve the fully constructed cron expression string from a `CronBuilder` instance. This is useful for debugging or logging the scheduled time. ```apex CronBuilder cron = new CronBuilder() .everyDay(14, 0); String cronExpr = cron.getCronExpression(); // Returns: "0 0 14 * * ? *" ``` -------------------------------- ### Get Queueable Context with Default Fallback Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Retrieves and removes a queueable context. If a specific mock for the ID is exhausted, it falls back to the default mock. Use this to simulate queueable execution. ```apex AsyncMock.whenQueueableDefault().thenReturn(new AsyncMock.MockQueueableContext()); AsyncMock.whenQueueable('special').thenReturn(new AsyncMock.MockQueueableContext()); QueueableContext ctx1 = AsyncMock.getQueueableContext('special'); QueueableContext ctx2 = AsyncMock.getQueueableContext('special'); Assert.isNotNull(ctx1); Assert.isNotNull(ctx2); // Falls back to default ``` -------------------------------- ### Commit and Push Changes Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/CONTRIBUTING.md Stage all changes, commit them with a conventional commit message, and push the branch to your fork. ```bash git add . git commit -m "feat: add support for XYZ feature" git push origin feature/my-awesome-feature ``` -------------------------------- ### Get Finalizer Context with Default Fallback Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Retrieves and removes a finalizer context. If a specific mock for the ID is exhausted, it falls back to the default mock. Use this to simulate finalizer execution. ```apex AsyncMock.whenFinalizerDefault().thenReturn(ParentJobResult.SUCCESS); AsyncMock.whenFinalizer('special').thenThrow(new DmlException('Error')); FinalizerContext ctx1 = AsyncMock.getFinalizerContext('special'); FinalizerContext ctx2 = AsyncMock.getFinalizerContext('special'); Assert.areEqual(ParentJobResult.UNHANDLED_EXCEPTION, ctx1.getResult()); Assert.areEqual(ParentJobResult.SUCCESS, ctx2.getResult()); // Falls back to default ``` -------------------------------- ### BatchableBuilder.execute Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/batchable.md Executes the batch job with the configured options. Returns an Async.Result. ```APIDOC ## execute ### Description Executes the batch job with the configured options. Returns an Async.Result. ### Signature ```apex Async.Result execute(); ``` ### Example ```apex Async.Result result = Async.batchable(new MyBatchJob()) .scopeSize(100) .execute(); ``` Returns `result.salesforceJobId` containing the Salesforce Job Id. ``` -------------------------------- ### Mock Queueable Job Context Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Sets up a mock for a specific queueable job identified by mockId. Use this when you need to control the behavior of a particular queueable job during testing. ```apex AsyncMock.whenQueueable('account-creator') .thenReturn(new AsyncMock.MockQueueableContext()); ``` -------------------------------- ### Build MockFinalizerContext with Exception Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Constructs a MockFinalizerContext, setting both the result to UNHANDLED_EXCEPTION and providing a specific exception. This is used for detailed error simulation in finalizers. ```apex ErrorHandlerFinalizer finalizer = new ErrorHandlerFinalizer(); finalizer.finalizerCtx = new AsyncMock.MockFinalizerContext() .setResult(ParentJobResult.UNHANDLED_EXCEPTION) .setException(new DmlException('Direct test error')); finalizer.work(); ``` -------------------------------- ### Build Multiple Cron Instances for Every X Minutes Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/schedulable.md Use `buildForEveryXMinutes` to create multiple `CronBuilder` instances that run every X minutes, up to a maximum of 30 minutes. This is ideal for frequent, short-interval tasks. ```apex CronBuilder baseCron = new CronBuilder().hour('9'); List crons = baseCron.buildForEveryXMinutes(15); // Runs every 15 minutes during hour 9 ``` -------------------------------- ### Execute Batch Job Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/batchable.md Execute the batch job with the configured options using the `execute` method. The `salesforceJobId` is available in the returned Async.Result. ```apex Async.Result result = Async.batchable(new MyBatchJob()) .scopeSize(100) .execute(); ``` -------------------------------- ### Async Lib Internal Cloning Process Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/job-cloning.md Illustrates the internal mechanism of Async Lib where it clones a job instance before adding it to the processing queue. ```apex // Your code Async.queueable(myJob).enqueue(); // What happens internally QueueableJob clonedJob = myJob.clone(); // Creates a separate instance // Add clonedJob to the processing queue ``` -------------------------------- ### Prefer Direct Testing Over Integration Testing Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/testing-async-jobs.md Compares the performance and focus of direct unit testing versus full integration testing for asynchronous jobs. Direct testing is recommended for speed and isolation. ```apex // Faster - direct unit test @IsTest static void directTest() { MyJob job = new MyJob(); job.queueableCtx = new AsyncMock.MockQueueableContext(); job.work(); // Assert results } // Slower - full integration test @IsTest static void integrationTest() { Test.startTest(); Async.queueable(new MyJob()).enqueue(); Test.stopTest(); // Assert results } ``` -------------------------------- ### Initialize Batchable Job Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/batchable.md Use the `batchable` method to construct a new BatchableBuilder instance with the specified batchable job. ```apex Async.batchable(new MyBatchJob()); ``` -------------------------------- ### Mock Queueable Context for Integration-Style Testing Source: https://context7.com/beyond-the-cloud-dev/async-lib/llms.txt Use this pattern to mock a queueable context when testing jobs that are enqueued and processed within Test.startTest() and Test.stopTest(). ```apex @IsTest static void shouldProcessAccountsWithMockedContext() { AsyncMock.whenQueueable('account-processor') .thenReturn(new AsyncMock.MockQueueableContext().setJobId('707xx0000000001AAA')); Test.startTest(); Async.queueable(new AccountProcessorJob(new List{ '0013000000abcdef' })) .mockId('account-processor') .enqueue(); Test.stopTest(); Assert.areEqual(1, [SELECT COUNT() FROM Account WHERE Description != null]); } ``` -------------------------------- ### Schedulable Initialization Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/schedulable.md Constructs a new SchedulableBuilder instance with the specified schedulable job. ```APIDOC ## schedulable ### Description Constructs a new SchedulableBuilder instance with the specified schedulable job. ### Signature ```apex Async schedulable(Schedulable scheduleJob); ``` ### Strict Example ```apex Async.schedulable(new MySchedulableJob()); ``` ### Batchable Conversion Example ```apex Async.batchable(new MyBatchJob()) .asSchedulable(); ``` ### Queueable Conversion Example ```apex Async.queueable(new MyQueueableJob()) .asSchedulable(); ``` ``` -------------------------------- ### Schedule a Job with Cron Expression Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/schedulable.md Use the `schedule` method to deploy the configured job. It returns a list of `Async.Result` objects, each containing the Salesforce Job Id for the scheduled cron expression. ```apex List results = Async.schedulable(new MySchedulableJob()) .name('Every Hour Processing') .cronExpression(new CronBuilder().everyHour(1)) .schedule(); ``` -------------------------------- ### Create a New Feature Branch Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/CONTRIBUTING.md Create a new branch for your feature or bug fix. Use a descriptive name for the branch. ```bash git checkout -b feature/my-awesome-feature ``` -------------------------------- ### thenThrow (FinalizerMockSetup) Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Creates a MockFinalizerContext with UNHANDLED_EXCEPTION result and the specified exception. This is used to simulate a finalizer throwing an exception during its execution. ```APIDOC ## thenThrow (FinalizerMockSetup) ### Description Creates a `MockFinalizerContext` with `UNHANDLED_EXCEPTION` result and the specified exception. ### Signature ```apex FinalizerMockSetup thenThrow(Exception ex); ``` ### Example ```apex AsyncMock.whenFinalizer('error-handler') .thenThrow(new DmlException('Parent job failed')); Test.startTest(); Async.queueable(new ParentJobWithFinalizer('error-handler')).enqueue(); Test.stopTest(); Account errorLog = [SELECT Name, Description FROM Account LIMIT 1]; Assert.areEqual('Parent job failed', errorLog.Description); ``` ``` -------------------------------- ### Serialization Failure in Package Code Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/deep-clone-in-packages.md Attempting to serialize a job instance from within the package code (`btcdev` namespace) can fail due to internal platform metadata that is not serializable. ```apex // Inside btcdev.QueueableJob.cloneForDeepCopy() JSON.serialize(this); // System.JSONException: Type cannot be serialized ``` -------------------------------- ### Test Default Mock Fallback for Jobs Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/testing-async-jobs.md Demonstrates using `AsyncMock.whenFinalizerDefault` to provide a fallback mock behavior for jobs that do not have specific mock configurations. Useful for testing scenarios where most jobs follow a standard pattern. ```apex @IsTest static void shouldUseDefaultMock() { AsyncMock.whenFinalizerDefault() .thenReturn(ParentJobResult.SUCCESS); Test.startTest(); // All these jobs use the default mock Async.queueable(new ParentJobWithFinalizer('job-1')).enqueue(); Async.queueable(new ParentJobWithFinalizer('job-2')).enqueue(); Test.stopTest(); Assert.areEqual(0, [SELECT COUNT() FROM Account]); } ``` -------------------------------- ### Schedule Batch Job Minutes From Now Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/batchable.md Schedule the batch job to run after a specified number of minutes using the `minutesFromNow` method. ```apex Async.batchable(new MyBatchJob()) .minutesFromNow(10); ``` -------------------------------- ### Mock Default Queueable Job Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Sets up a default mock for queueable jobs that applies when no specific mockId matches or when a specific mock is exhausted. This is useful for general-purpose mocking. ```apex AsyncMock.whenQueueableDefault() .thenReturn(new AsyncMock.MockQueueableContext()); ``` -------------------------------- ### Configure Advanced Error Handling for Jobs Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/getting-started.md Set up robust error handling for asynchronous jobs using Async Lib. Options include continuing on enqueue or execute failures, and rolling back DML operations upon execution failure. ```apex 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(); ``` -------------------------------- ### Direct Unit Test with Mocked Queueable Context Source: https://context7.com/beyond-the-cloud-dev/async-lib/llms.txt This pattern allows direct testing of a Queueable job's work() method by injecting a mock context, bypassing the need for Test.startTest(). ```apex @IsTest static void shouldCreateAccountDirectly() { AccountCreatorJob job = new AccountCreatorJob('Test Account'); job.queueableCtx = new AsyncMock.MockQueueableContext(); // inject mock context job.work(); // call work() directly Account acc = [SELECT Name FROM Account LIMIT 1]; Assert.areEqual('Test Account', acc.Name); } ``` -------------------------------- ### Execute Batch Job with Async.batchable() Source: https://context7.com/beyond-the-cloud-dev/async-lib/llms.txt Wrap Database.Batchable jobs using Async.batchable() for scope size configuration and delayed execution. Can be converted to a schedulable for cron-based execution. ```apex public class AccountCleanupBatch implements Database.Batchable { public Database.QueryLocator start(Database.BatchableContext ctx) { return Database.getQueryLocator([SELECT Id, Description FROM Account WHERE Description = null]); } public void execute(Database.BatchableContext ctx, List scope) { for (Account acc : scope) { acc.Description = 'Cleaned up'; } update scope; } public void finish(Database.BatchableContext ctx) { System.debug('Batch complete: ' + ctx.getJobId()); } } // Execute immediately with scope size 200 Async.Result result = Async.batchable(new AccountCleanupBatch()) .scopeSize(200) .execute(); System.debug('Batch Job ID: ' + result.salesforceJobId); // Execute after a delay Async.batchable(new AccountCleanupBatch()) .scopeSize(100) .minutesFromNow(15) .execute(); // Convert to schedulable for cron-based execution Async.batchable(new AccountCleanupBatch()) .scopeSize(200) .asSchedulable() .name('Nightly Account Cleanup') .cronExpression(new CronBuilder().everyDay(2, 0)) // daily at 2:00 AM .schedule(); ``` -------------------------------- ### Convert to Schedulable Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/queueable.md Converts the queueable builder to a schedulable builder for cron-based scheduling. ```APIDOC ## asSchedulable Converts the queueable builder to a schedulable builder for cron-based scheduling. See [Schedulable API](/api/schedulable) for scheduling options. ### Signature ```apex SchedulableBuilder asSchedulable(); ``` ### Example ```apex Async.queueable(new MyQueueableJob()) .asSchedulable(); ``` ``` -------------------------------- ### Handling More Than 50 Queueable Jobs Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/initial-scheduled-queuable-batch-job.md Illustrates the problem when enqueuing more than 50 queueable jobs in a single transaction. This scenario requires a fallback mechanism to avoid hitting the limit. ```apex Integer jobCount = 0; // We're at 49 jobs enqueued Async.queueable(new Job50()).enqueue(); // This works fine // But what happens next? // We need to handle these cases to avoid hitting the 50 job limit Async.queueable(new Job51()).enqueue(); // We need to handle this! Async.queueable(new Job52()).enqueue(); // And this! Async.queueable(new Job53()).enqueue(); // And this...? // ... potentially many more jobs Async.queueable(new JobXXXXX()).enqueue(); // How many more...? ``` -------------------------------- ### Enqueue a Queueable Job Source: https://context7.com/beyond-the-cloud-dev/async-lib/llms.txt Use `Async.queueable()` to create and enqueue a `QueueableJob`. The `enqueue()` method returns an `Async.Result` object containing job details. You can configure priority, delay, and asynchronous options. ```apex public class OrderProcessingJob extends QueueableJob { private List orderIds; public OrderProcessingJob(List orderIds) { this.orderIds = orderIds; } public override void work() { // process orders... } } // Basic enqueue Async.Result result = Async.queueable(new OrderProcessingJob(orderIds)).enqueue(); System.debug('Custom Job ID: ' + result.customJobId); // => Custom Job ID: 550e8400-e29b-41d4-a716-446655440000 ``` ```apex // With priority and delay Async.Result result2 = Async.queueable(new OrderProcessingJob(orderIds)) .priority(1) // lower number = higher priority .delay(5) // execute in 5 minutes .enqueue(); ``` ```apex // With AsyncOptions instead of delay AsyncOptions opts = new AsyncOptions(); opts.MaximumQueueableStackDepth = 5; Async.Result result3 = Async.queueable(new OrderProcessingJob(orderIds)) .asyncOptions(opts) .enqueue(); ``` ```apex // Result properties System.debug(result.salesforceJobId); // Salesforce job ID System.debug(result.customJobId); // UUID assigned by framework System.debug(result.asyncType); // Async.AsyncType.QUEUEABLE System.debug(result.queueableChainState.enqueueType); // => NEW_CHAIN | EXISTING_CHAIN | INITIAL_QUEUEABLE_CHAIN_SCHEDULABLE ``` -------------------------------- ### Async.queueable() - Error Handling Options Source: https://context7.com/beyond-the-cloud-dev/async-lib/llms.txt Configure per-job error handling strategies to control whether a job failure halts or continues the chain, and whether DML should be rolled back. ```APIDOC ## Async.queueable() — Error Handling Options Configure per-job error handling strategies to control whether a job failure halts or continues the chain, and whether DML should be rolled back. ```apex Async.Result result = Async.queueable(new RiskyProcessingJob()) .continueOnJobEnqueueFail() // chain continues even if this job fails to enqueue .continueOnJobExecuteFail() // chain continues even if this job throws during work() .rollbackOnJobExecuteFail() // rolls back all DML if this job throws during work() .enqueue(); ``` ``` -------------------------------- ### thenReturn (QueueableContext) Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Adds a QueueableContext to the mock queue. Each call to getQueueableContext consumes one context from the queue in a First-In, First-Out (FIFO) manner. ```APIDOC ## thenReturn (QueueableContext) ### Description Adds a `QueueableContext` to the mock queue. Each call to `getQueueableContext` consumes one context from the queue (FIFO). ### Signature ```apex QueueableMockSetup thenReturn(QueueableContext ctx); ``` ### Example ```apex AsyncMock.whenQueueable('my-job') .thenReturn(new AsyncMock.MockQueueableContext().setJobId('707xx0000000001')); ``` ``` -------------------------------- ### Schedule Method Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/schedulable.md Executes the scheduling of the configured job. ```APIDOC ## schedule ### Description Executes the scheduling of the configured job. This method should be called after all builder methods have been set. ### Signature ```apex List schedule(); ``` ### Example ```apex List results = Async.schedulable(job) .name('Daily Processing Job') .cronExpression('0 0 2 * * ? *') .skipWhenAlreadyScheduled() .schedule(); System.debug('Scheduled job results: ' + results); ``` ``` -------------------------------- ### Schedulable Builder Methods Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/schedulable.md Methods for configuring the Schedulable job, such as setting its name and cron expression. ```APIDOC ## name ### Description Sets the name for the scheduled job. This is required for scheduling. ### Signature ```apex SchedulableBuilder name(String name); ``` ### Example ```apex Async.schedulable(new MySchedulableJob()) .name('Daily Cleanup Job'); ``` ## cronExpression string ### Description Sets a cron expression for scheduling the job. Can be called multiple times to schedule at different intervals. ### Signature ```apex SchedulableBuilder cronExpression(String cronExpression); ``` ### Example ```apex Async.schedulable(new MySchedulableJob()) .name('Hourly Job') .cronExpression('0 0 * * * ? *'); ``` ## cronExpression builder ### Description Sets a cron expression using a CronBuilder for more advanced scheduling configuration. ### Signature ```apex SchedulableBuilder cronExpression(CronBuilder builder); ``` ### Example ```apex CronBuilder cron = new CronBuilder().everyHour(1); Async.schedulable(new MySchedulableJob()) .name('Nightly Job') .cronExpression(cron); ``` ## cronExpression multiple builders ### Description Sets multiple cron expressions using a list of CronBuilder instances for complex scheduling scenarios. ### Signature ```apex SchedulableBuilder cronExpression(List builders); ``` ### Example ```apex List crons = new List{ new CronBuilder().everyHour(0), new CronBuilder().everyDay(0, 0) }; Async.schedulable(new MySchedulableJob()) .name('Business Hours Job') .cronExpression(crons); ``` ## skipWhenAlreadyScheduled ### Description If set, the job will not be scheduled if it is already scheduled with the same name. This prevents throwing the `System.AsyncException`. ### Signature ```apex SchedulableBuilder skipWhenAlreadyScheduled(); ``` ### Example ```apex Async.schedulable(new MySchedulableJob()) .skipWhenAlreadyScheduled(); ``` ``` -------------------------------- ### whenFinalizer Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md Sets up a mock for a specific finalizer identified by mockId. This allows you to control the behavior of a particular finalizer during testing. ```APIDOC ## whenFinalizer(String mockId) ### Description Sets up a mock for a specific finalizer identified by mockId. ### Signature ```apex static FinalizerMockSetup whenFinalizer(String mockId); ``` ### Example ```apex AsyncMock.whenFinalizer('error-handler') .thenReturn(ParentJobResult.SUCCESS); ``` ``` -------------------------------- ### Mock Queueable with Job ID (Convenience) Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/async-mock.md A simplified method to mock a queueable job by directly providing the job ID. This is a shortcut for creating a MockQueueableContext. ```apex AsyncMock.whenQueueable('my-job') .thenReturn('707xx0000000001AAA'); ``` -------------------------------- ### Test Async Job Success and Failure Paths Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/explanations/testing-async-jobs.md Use AsyncMock to simulate successful and failed outcomes of an async job's finalizer. This ensures your job logic correctly handles both scenarios. ```apex @IsTest static void shouldHandleSuccess() { AsyncMock.whenFinalizer('handler').thenReturn(ParentJobResult.SUCCESS); // Test success path } ``` ```apex @IsTest static void shouldHandleFailure() { AsyncMock.whenFinalizer('handler').thenThrow(new DmlException('Failed')); // Test error handling path } ``` -------------------------------- ### Async.batchable Source: https://github.com/beyond-the-cloud-dev/async-lib/blob/main/website/api/batchable.md Constructs a new BatchableBuilder instance with the specified batchable job. ```APIDOC ## batchable ### Description Constructs a new BatchableBuilder instance with the specified batchable job. ### Signature ```apex Async batchable(Database.Batchable job); ``` ### Example ```apex Async.batchable(new MyBatchJob()); ``` ```