Skip to main content

Salesforce Apex Flex Queue: Batch Job Management, Limits & Reordering Guide

In plain words: Think of the Apex Flex Queue as a digital waiting room for your batch jobs. Salesforce can run up to 5 batch jobs at the same time. The Flex Queue holds up to 100 additional batch jobs in a Holding status, automatically feeding them into execution as processing slots open up.

Managing large-scale data processing in Salesforce requires balancing high data volumes with strict multi-tenant governor limits. While synchronous transactions must complete within milliseconds, Batch Apex handles millions of records asynchronously. The Apex Flex Queue is the core platform infrastructure that governs how these batch jobs are queued, prioritized, and executed without failing due to concurrency constraints.

1. How the Apex Flex Queue Operates

Prior to the Flex Queue, submitting a batch job when all processing threads were full resulted in immediate job rejection. The Flex Queue eliminates this limitation by introducing the Holding status:

  • Holding Status: When you call Database.executeBatch(), the job enters the Flex Queue in the Holding state if all 5 concurrent execution slots are occupied.
  • Up to 100 Queued Jobs: The Flex Queue can hold up to 100 batch jobs simultaneously in the Holding state per organization.
  • Automatic Dispatching: As running jobs complete or fail, Salesforce automatically pulls jobs from the top of the Flex Queue and transitions their status from Holding to Queued, then Preparing, and finally Processing.
360 Asynchronous Architecture & Limits Card:
  • Concurrent Processing Limit: Exactly 5 Batch Apex jobs can run simultaneously in Processing or Preparing status.
  • Flex Queue Capacity: Holds up to 100 batch jobs in Holding status.
  • Daily 24-Hour Execution Limit: 250,000 asynchronous executions or 200 × total user licenses (whichever is greater).
  • Job Reordering Support: Jobs in the Holding status can be reordered programmatically or declaratively; active jobs cannot.

2. Programmatic Reordering with the System.FlexQueue Class

Salesforce provides the System.FlexQueue class, allowing developers to dynamically adjust the execution order of queued batch jobs based on business urgency (e.g., pushing critical nightly billing runs ahead of general data cleanups).

  • FlexQueue.moveBeforeJob(jobToMoveId, targetJobId): Moves a holding job directly ahead of another holding job in the queue.
  • FlexQueue.moveAfterJob(jobToMoveId, targetJobId): Places a holding job directly after another specified holding job.
  • FlexQueue.moveJobToFront(jobId): Promotes a holding job to Position 1 so it becomes the next job to execute.
  • FlexQueue.moveJobToEnd(jobId): Deprioritizes a holding job by sending it to the back of the queue.
Real-World Example: Enqueuing & Promoting a High-Priority Batch Job
Submitting an invoice generation batch and promoting it to the front of the Flex Queue:
public with sharing class InvoiceBatchManager {
    public static void submitPriorityBillingRun() {
        // 1. Submit Batch Job
        DailyInvoiceBatch batchInstance = new DailyInvoiceBatch();
        Id batchJobId = Database.executeBatch(batchInstance, 200);

        // 2. Check if the job was placed in the Holding state
        AsyncApexJob jobInfo = [
            SELECT Id, Status, JobType 
            FROM AsyncApexJob 
            WHERE Id = :batchJobId 
            WITH USER_MODE 
            LIMIT 1
        ];

        // 3. Promote to Position 1 if currently in the Flex Queue
        if (jobInfo.Status == 'Holding') {
            Boolean isMoved = System.FlexQueue.moveJobToFront(batchJobId);
            if (isMoved) {
                System.debug(LoggingLevel.INFO, 'Batch job successfully prioritized to Position 1 in Flex Queue: ' + batchJobId);
            }
        }
    }
}

3. Declarative Management & UI Monitoring

Administrators and release managers can monitor and reorder holding jobs directly in Salesforce Setup without writing code:

  1. Navigate to Setup > in the Quick Find box, enter Apex Flex Queue.
  2. Click Apex Flex Queue to view all batch jobs currently in the Holding status.
  3. Use the Reorder action buttons (or drag-and-drop handles) to move critical jobs to higher positions.
  4. To monitor actively running and completed jobs, navigate to Setup > Apex Jobs.

4. Common Developer Traps & Best Practices

Developer Trap: Reordering Active Jobs & Flex Queue Overflow
Calling System.FlexQueue.moveJobToFront() on a job whose status has already transitioned to Queued, Preparing, or Processing will return false and have no effect. Additionally, attempting to submit a batch job when the Flex Queue already contains 100 holding jobs throws a fatal System.AsyncException: Too many batch jobs in the queue.
Core Rule: Verify that the Flex Queue has available holding capacity before submitting batch jobs programmatically, and only invoke System.FlexQueue reordering methods on jobs confirmed to be in Holding status.
  • Check Queue Capacity Proactively: Query [SELECT count() FROM AsyncApexJob WHERE Status = 'Holding'] before enqueueing non-urgent data processing jobs.
  • Choose the Right Asynchronous Tool: Use Batch Apex when processing large tables exceeding 50,000 records; use Queueable Apex for sequential job chaining, external REST callouts, and smaller asynchronous workloads.
  • Size Batch Chunks Appropriately: The default batch size is 200 records. For lightweight records, increase the chunk size up to 2,000 to process data faster; for heavy trigger chains, reduce chunk size to prevent CPU timeout exceptions.

Summary

The Apex Flex Queue provides a scalable buffer for high-volume Salesforce data processing. By understanding the 5-job concurrent execution cap, taking advantage of the 100-job holding capacity, and using the System.FlexQueue class to prioritize mission-critical tasks, you can design resilient, automated architectures that process enterprise workloads efficiently.