16

Is there any execution context which uses asynchronous governor limits and allows up to 50 jobs to be queued with System.enqueueJob in a single transaction, or is Salesforce’s documentation just wrong?

Since API v32.0, the primary documentation for governor limits has stated that the:

"maximum number of Apex jobs added to the queue with System.enqueueJob" is 50 in both synchronous and asynchronous contexts.

I have tested this in every asynchronous context that I’m aware of, and it appears that the true limit on asynchronous use of System.enqueueJob is actually 1.

Test Queueable Used:

public class QueueableTest implements Queueable{    
    public void execute(QueueableContext context){ 
        System.debug('do stuff');        
    }   
}

Test future method:

@future
public static void futureTest(){
    Id jobId1 = System.enqueueJob(new QueueableTest());
    Id jobId2 = System.enqueueJob(new QueueableTest());
}

Test batch job (tested start, execute, and finish independently):

public class BatchTest implements Database.Batchable<sObject> {    

    public Database.QueryLocator start(Database.BatchableContext bc){
        Id jobId1 = System.enqueueJob(new QueueableTest());
        Id jobId2 = System.enqueueJob(new QueueableTest());
        String q = 'SELECT Id FROM Contact LIMIT 1';
        return Database.getQueryLocator(q);
    }

    public void execute(Database.BatchableContext bc, List<Contact> scope){     
        Id jobId1 = System.enqueueJob(new QueueableTest());
        Id jobId2 = System.enqueueJob(new QueueableTest());        
    }

    public void finish(Database.BatchableContext bc){
        Id jobId1 = System.enqueueJob(new QueueableTest());
        Id jobId2 = System.enqueueJob(new QueueableTest());
    }  
}

Test from another queueable:

public class QueueableTest2 implements Queueable{    
    public void execute(QueueableContext context){ 
        Id jobId1 = System.enqueueJob(new QueueableTest());
        Id jobId2 = System.enqueueJob(new QueueableTest());   
    }
}

In all of the above, I get the following error:

FATAL_ERROR System.LimitException: Too many queueable jobs added to the queue: 2

It does appear to be possible to enqueue multiple jobs from a schedulable, like this:

public class SchedulableTest implements Schedulable{    
    public void execute(SchedulableContext sc){
        Id jobId1 = System.enqueueJob(new QueueableTest());
        Id jobId2 = System.enqueueJob(new QueueableTest());
    }
}

However, it is already established that scheduled apex uses synchronous governor limits.

So what am I missing here? I am not asking why the limit would be 1. I just want to know whether I've misunderstood something or if the documentation is inaccurate.

3
  • 4
    I've informed the documentation team of that. You're right, everywhere else it says "the limit is 1" except for the most obvious place.
    – sfdcfox
    Apr 25, 2017 at 20:43
  • Thanks @sfdcfox ... I just bumped into this today, and my immediate reaction is one of exasperated disbelief. I guess I should be thankful that you logged the case with Salesforce that I didn't have to, although I think I'm going to log a case anyway just to put more pressure on the team. I mean, come on! How many trained monkeys does it take to fix documentation that's obviously and painfully wrong?!
    – Marty C.
    May 22, 2017 at 15:45
  • 1
    Also the documentation is not just wrong in a single place. It's wrong on both the Apex Governor Limits page and the Queueable Apex page.
    – Marty C.
    May 22, 2017 at 15:51

2 Answers 2

11

Yes, the documentation in question is incorrect. You can prove that the Limits class does not conform to what is written therein fairly easily:

public class Demo implements Queueable
{
    public void execute(QueueableContext context)
    {
        system.assertEquals(1, Limits.getLimitQueueableJobs());
    }
    @future
    public static void doStuff()
    {
        system.assertEquals(1, Limits.getLimitQueueableJobs());
    }
}

Proving it for batches is a fairly straightforward alteration of the above.


Some pieces of the documentation, however, do touch on this point in a way that properly explains the governor limits involved. They are somewhat lacking in clarity, but you can only execute one job from within a job. Here's one such example:

Chaining Jobs

If you need 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:

public class AsyncExecutionExample implements Queueable {
    public void execute(QueueableContext context) {
        // Your processing logic here       

        // Chain this job to next job by submitting the next job
        System.enqueueJob(new SecondJob());
    }
}

Also from the same document:

When chaining jobs, you can add only one job from an executing job with System.enqueueJob, which means that only one child job can exist for each parent queueable job. Starting multiple child jobs from the same queueable job isn’t supported.

1
  • 2
    The point here though, is that the documentation suggests that you can do something you really can't do.
    – sfdcfox
    Apr 25, 2017 at 20:37
-1

we can enqueue up to 50 times from a synchronous context enter image description here

1
  • 1
    The person who asked the question already knows this, and even points to documentation to support it. The question here is about making calls from an asynchronous context.
    – Derek F
    Jan 6, 2022 at 12:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .