Newer Version Available

This content describes an older version of this product. View Latest

Queueable Apex

Take control of your asynchronous Apex processes by using the Queueable interface. Salesforce recommends that you use Queueable Apex instead of Apex future methods. Queueables have the same use cases as future methods but offer extra benefits, including job IDs, support for non-primitive types, and job chaining.

Apex processes that run for a long time, such as extensive database operations or external web service callouts, can be run asynchronously by implementing the Queueable interface and adding a job to the Apex job queue. In this way, your asynchronous Apex job runs in the background in its own thread and doesn’t delay the execution of your main Apex logic. Each queued job runs when system resources become available. A benefit of using the Queueable interface methods is that some governor limits are higher than for synchronous Apex, such as heap size limits.

If an Apex transaction rolls back, any queueable jobs queued for execution by the transaction aren’t processed.

Important

Queueable jobs are similar to future methods in that they’re both queued for execution, but they provide you with these additional benefits.

  • Getting an ID for your job: When you submit your job by invoking the System.enqueueJob method, the method returns the ID of the new job. This ID corresponds to the ID of the AsyncApexJob record. Use this ID to identify and monitor your job, either through the Salesforce UI (Apex Jobs page), or programmatically by querying your record from AsyncApexJob.
  • Using non-primitive types: Your queueable class can contain member variables of non-primitive data types, such as sObjects or custom Apex types. Those objects can be accessed when the job executes.
  • Chaining jobs: You can chain one job to another job by starting a second job from a running job. Chaining jobs is useful if your process depends on another process to have run first.

You can set a maximum stack depth of chained Queueable jobs, overriding the default limit of five in Developer and Trial Edition organizations.

Variables that are declared transient are ignored by serialization and deserialization and the value is set to null in Queueable Apex.

Note

Adding a Queueable Job to the Asynchronous Execution Queue

This example implements the Queueable interface. The execute method in this example inserts a new account. The System.enqueueJob(queueable) method is used to add the job to the queue.
1public with sharing class AsyncExecutionExample implements Queueable {
2    public void execute(QueueableContext context) {
3        Account a = new Account(Name='Acme',Phone='(415) 555-1212');
4        insert as user a;        
5    }
6}
To add this class as a job on the queue, call this method:
1ID jobID = System.enqueueJob(new AsyncExecutionExample());

When you call System.enqueueJob, Salesforce adds the process to the queue. Actual execution can be delayed based on service availability.

Important

After you submit your queueable class for execution, the job is added to the queue and will be processed when system resources become available. You can monitor the status of your job programmatically by querying AsyncApexJob or through the user interface in Setup by entering Apex Jobs in the Quick Find box, then selecting Apex Jobs.

To query information about your submitted job, perform a SOQL query on AsyncApexJob by filtering on the job ID that the System.enqueueJob method returns. This example uses the jobID variable that was obtained in the previous example.

1AsyncApexJob jobInfo = [SELECT Status,NumberOfErrors FROM AsyncApexJob WHERE Id = :jobID WITH USER_MODE];

Similar to future jobs, queueable jobs don’t process batches, and so the number of processed batches and the number of total batches are always zero.

Adding a Queueable Job with a Specified Minimum Delay

Use the System.enqueueJob(queueable, delay) method to add queueable jobs to the asynchronous execution queue with a specified minimum delay (0–10 minutes). The delay is ignored during Apex testing.

See System.enqueueJob(queueable, delay) in the Apex Reference Guide.

When you set the delay to 0 (zero), the queueable job is run as quickly as possible. With chained queueable jobs, implement a mechanism to slow down or halt the job if necessary. Without such a fail-safe mechanism in place, you can rapidly reach the daily async Apex limit.

Warning

In the following cases, it would be beneficial to adjust the timing before the queueable job is run.

  • If the external system is rate-limited and can be overloaded by chained queueable jobs that are making rapid callouts.
  • When polling for results, and executing too fast can cause wasted usage of the daily async Apex limits.

This example adds a job for delayed asynchronous execution by passing in an instance of your class implementation of the Queueable interface for execution. There’s a minimum delay of 5 minutes before the job is executed.

1Integer delayInMinutes = 5;
2ID jobID = System.enqueueJob(new MyQueueableClass(), delayInMinutes);

Admins can define a default org-wide delay (1–600 seconds) in scheduling queueable jobs that were scheduled without a delay parameter. Use the delay setting as a mechanism to slow default queueable job execution. If the setting is omitted, Apex uses the standard queueable timing with no added delay.

Using the System.enqueueJob(queueable, delay) method ignores any org-wide enqueue delay setting.

Note

Define the org-wide delay in one of these ways.

  • From Setup, in the Quick Find box, enter Apex Settings, and then enter a value (1–600 seconds) for Default minimum enqueue delay (in seconds) for queueable jobs that do not have a delay parameter
  • To enable this feature programmatically with Metadata API, see ApexSettings in the Metadata API Developer Guide.

Adding a Queueable Job with a Specified Stack Depth

Use the System.enqueueJob(queueable, asyncOptions) method where you can specify the maximum stack depth and the minimum queue delay in the asyncOptions parameter.

The System.AsyncInfo class properties contain the current and maximum stack depths and the minimum queueable delay.

The System.AsyncInfo class has methods to help you determine if maximum stack depth is set in your Queueable request and to get the stack depths and queue delay for your queueables that are currently running. Use information about the current queueable execution to make decisions on adjusting delays on subsequent calls.

These are methods in the System.AsyncInfo class.

  • hasMaxStackDepth()
  • getCurrentQueueableStackDepth()
  • getMaximumQueueableStackDepth()
  • getMinimumQueueableDelayInMinutes()

This example uses stack depth to terminate a chained job and prevent it from reaching the daily maximum number of asynchronous Apex method executions.

1// Fibonacci
2public with sharing class FibonacciDepthQueueable implements Queueable {
3   
4    private long nMinus1, nMinus2;
5       
6    public static void calculateFibonacciTo(integer depth) {
7        AsyncOptions asyncOptions = new AsyncOptions();
8        asyncOptions.MaximumQueueableStackDepth = depth;
9        System.enqueueJob(new FibonacciDepthQueueable(null, null), asyncOptions);
10    }
11       
12    private FibonacciDepthQueueable(long nMinus1param, long nMinus2param) {
13        nMinus1 = nMinus1param;
14        nMinus2 = nMinus2param;
15    }
16   
17    public void execute(QueueableContext context) {
18       
19        integer depth = AsyncInfo.getCurrentQueueableStackDepth();
20       
21        // Calculate step
22        long fibonacciSequenceStep;
23        switch on (depth) {
24            when 1, 2 {
25                fibonacciSequenceStep = 1;
26            }
27            when else {
28                fibonacciSequenceStep = nMinus1 + nMinus2;
29            }
30        }
31       
32        System.debug('depth: ' + depth + ' fibonacciSequenceStep: ' + fibonacciSequenceStep);
33       
34        if(System.AsyncInfo.hasMaxStackDepth() &&
35           AsyncInfo.getCurrentQueueableStackDepth() >= 
36           AsyncInfo.getMaximumQueueableStackDepth()) {
37            // Reached maximum stack depth
38            Fibonacci__c result = new Fibonacci__c(
39                Depth__c = depth,
40                Result = fibonacciSequenceStep
41                );
42            insert as user result;
43        } else {
44            System.enqueueJob(new FibonacciDepthQueueable(fibonacciSequenceStep, nMinus1));
45        }
46    }
47}

Testing Queueable Jobs

This example shows how to test the execution of a queueable job in a test method. A queueable job is an asynchronous process. To make sure that this process runs within the test method, the job is submitted to the queue between the Test.startTest and Test.stopTest block. The system executes all asynchronous processes started in a test method synchronously after the Test.stopTest statement. Next, the test method verifies the results of the queueable job by querying the account that the job created.
1@IsTest
2public with sharing class AsyncExecutionExampleTest {
3    @IsTest
4    static void test1() {
5        // startTest/stopTest block to force async processes 
6        //   to run in the test.
7        Test.startTest();        
8        System.enqueueJob(new AsyncExecutionExample());
9        Test.stopTest();
10        
11        // Validate that the job has run
12        // by verifying that the record was created.
13        // This query returns only the account created in test context by the 
14        // Queueable class method.
15        Account acct = [SELECT Name,Phone FROM Account WHERE Name='Acme' LIMIT 1 WITH USER_MODE];
16        Assert.isNotNull(acct);
17        Assert.areEqual('(415) 555-1212', acct.Phone);
18    }
19}

Chaining Jobs

To run a job after some other processing is done first by another job, you can chain queueable jobs. To chain a job to another job, submit the second job from the execute() method of your queueable class. You can add only one job from an executing job, which means that only one child job can exist for each parent job. For example, if you have a second class called SecondJob that implements the Queueable interface, you can add this class to the queue in the execute() method as follows:

1public with sharing class AsyncExecutionExample implements Queueable {
2    public void execute(QueueableContext context) {
3        // Your processing logic here       
4
5        // Chain this job to next job by submitting the next job
6        System.enqueueJob(new SecondJob());
7    }
8}

Apex allows HTTP and web service callouts from queueable jobs, if they implement the Database.AllowsCallouts marker interface. In queueable jobs that implement this interface, callouts are also allowed in chained queueable jobs.

Note

You can test chained queueable jobs by using appropriate stack depths, but be aware of applicable Apex governor limits. See Adding a Queueable Job with a Specified Stack Depth.

Queueable Apex Limits

  • The execution of a queued job counts one time against the shared limit for asynchronous Apex method executions. See Lightning Platform Apex Limits.
  • You can add up to 50 jobs to the queue with System.enqueueJob in a single transaction. In asynchronous transactions (for example, from a batch Apex job), you can add only one job to the queue with System.enqueueJob. To check how many queueable jobs have been added in one transaction, call Limits.getQueueableJobs().
  • Because no limit is enforced on the depth of chained jobs, you can chain one job to another. You can repeat this process with each new child job to link it to a new child job. For Developer Edition and Trial organizations, the maximum stack depth for chained jobs is 5, which means that you can chain jobs four times. The maximum number of jobs in the chain is 5, including the initial parent queueable job.
  • When chaining jobs with System.enqueueJob, you can add only one job from an executing job. Only one child job can exist for each parent queueable job. Starting multiple child jobs from the same queueable job isn’t supported.