Top 100 Asynchronous Apex & Batch Apex Interview Questions (2026)

⚡ Code-Heavy Deep Dive

Top 100 Asynchronous Apex & Batch Apex Interview Questions

Future Methods, Queueable Apex, Batch Apex, and Scheduled Apex — the four async tools every real Salesforce Developer interview eventually tests. Every question here includes genuine, working code, not just definitions.

Batch Apex specifically gets the deepest coverage, since it's the tool most interviews probe hardest — the three-method interface, stateful batches, chaining, and the governor limit nuances that trip up even experienced developers.

100
Questions
5
Categories
100+
Code Snippets
Category 1: Future Methods (18 Questions)
Q
Question 001 · Async Apex
What is a Future method and when would you use one?
✅ ANSWER

A Future method runs Apex code asynchronously in its own separate thread, outside the current transaction's limits. You use it specifically for callouts from a trigger context (since triggers cannot make callouts directly) or for lower-priority work that does not need to block the user's current operation.

💻 Future Method Declaration
public class CalloutHelper {
    @future(callout=true)
    public static void notifyExternalSystem(String accountId) {
        // Callout logic here
    }
}
🌍 Real World Example (XYZ Company)

An Account trigger needed to notify an external ERP system whenever a new Account was created, but triggers cannot make callouts directly. We wrapped the callout in a @future(callout=true) method called from the trigger handler.

🎤 One-Line Answer for Interview

"A Future method runs Apex asynchronously, mainly used to make callouts from a trigger context where direct callouts aren't allowed."

Q
Question 002 · Async Apex
What is the correct syntax to declare a Future method?
✅ ANSWER

Use the @future annotation directly above a method declaration. The method must be static and must return void.

💻 Correct Syntax
public class MyAsyncClass {
    @future
    public static void doAsyncWork(Set<Id> recordIds) {
        // logic here
    }
}
🌍 Real World Example (XYZ Company)

When building XYZ Company's lead enrichment process, we declared a static void method annotated with @future, taking a Set of Lead Ids as the only parameter.

🎤 One-Line Answer for Interview

"@future annotation above a static void method — that's the complete required syntax."

Q
Question 003 · Async Apex
Why must Future methods be static?
✅ ANSWER

Future methods execute in a completely separate thread with no access to the calling instance's state. Since there is no actual object instance carried over into that new thread, the method cannot be an instance method — it must be static.

🌍 Real World Example (XYZ Company)

A developer on our team initially tried writing a non-static Future method and got a compile error immediately, since the platform has no way to serialize and pass instance state into the new asynchronous thread.

🎤 One-Line Answer for Interview

"No instance state carries into the new thread, so the method must be static — there's no object instance to call it on."

Q
Question 004 · Async Apex
Why can Future methods only accept primitive data types as parameters, not sObjects directly?
✅ ANSWER

Future method calls are serialized and queued for asynchronous execution, and at the time they execute, the original data context may have changed or no longer exist in memory. Primitives (Id, String, Integer, Boolean, and collections of these) serialize cleanly; complex sObjects do not serialize reliably across that boundary.

💻 Valid Parameter Types
@future
public static void processRecords(Set<Id> recordIds) {
    List<Account> accounts = [SELECT Id, Name FROM Account WHERE Id IN :recordIds];
    // re-query fresh data instead of passing sObjects directly
}
🌍 Real World Example (XYZ Company)

Instead of passing Account records directly into a Future method, we passed only the Account Ids and re-queried fresh data inside the method — ensuring we always worked with current, accurate data.

🎤 One-Line Answer for Interview

"Future methods only accept primitives because sObjects can't serialize reliably across the async execution boundary — pass Ids, then re-query."

Q
Question 005 · Async Apex
Can a Future method call another Future method?
✅ ANSWER

No. Future methods cannot call other Future methods. Attempting this throws a runtime exception, since Salesforce does not allow nesting Future calls within an already-asynchronous Future context.

🌍 Real World Example (XYZ Company)

A developer tried chaining two Future methods together for a multi-step external sync process at XYZ Company, and it failed at runtime — we had to redesign using Queueable Apex instead, which genuinely supports chaining.

🎤 One-Line Answer for Interview

"No — Future methods cannot call other Future methods; Queueable Apex is the correct tool when you need chaining."

Q
Question 006 · Async Apex
What is the daily governor limit on Future method calls?
✅ ANSWER

An org can make up to 250,000 Future method calls (or licenses x a per-license limit, whichever is greater) per 24-hour period — but more practically relevant, only 50 Future method calls are allowed per single Apex transaction.

🌍 Real World Example (XYZ Company)

When XYZ Company's bulk Lead import triggered 500 Future calls in a single transaction, it immediately hit the 50-per-transaction limit — we had to refactor to a single Future call processing a full batch of Ids instead.

🎤 One-Line Answer for Interview

"50 Future calls per single transaction is the practical limit that actually matters day to day — bulkify by passing a collection, not one call per record."

Q
Question 007 · Async Apex
How do you make a Future method perform a callout (HTTP request)?
✅ ANSWER

Add callout=true as a parameter to the @future annotation. Without this explicit flag, attempting an HTTP callout inside a Future method throws a runtime exception.

💻 Future Method With Callout
@future(callout=true)
public static void sendToExternalAPI(String payload) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint('https://api.xyzcompany.com/sync');
    req.setMethod('POST');
    req.setBody(payload);
    Http http = new Http();
    HttpResponse res = http.send(req);
}
🌍 Real World Example (XYZ Company)

XYZ Company's Future method posting Opportunity data to an external billing system explicitly declared callout=true — omitting it caused an immediate CalloutException during testing.

🎤 One-Line Answer for Interview

"Add callout=true to the @future annotation — without it, any HTTP callout attempt inside the method throws an exception."

Q
Question 008 · Async Apex
What does @future(callout=true) do and when is it required?
✅ ANSWER

It explicitly grants the Future method permission to make external HTTP callouts. It's required any time the Future method's logic includes an HttpRequest/Http.send() call — Salesforce requires this explicit declaration as a safety measure.

🌍 Real World Example (XYZ Company)

We initially forgot the callout=true flag on a Future method calling XYZ Company's external tax calculation API, and every execution failed silently in the background until we checked Apex Jobs and found the error.

🎤 One-Line Answer for Interview

"callout=true explicitly grants permission for external HTTP calls — required whenever the Future method's body makes a callout."

Q
Question 009 · Async Apex
Can you track the status or completion of a Future method directly?
✅ ANSWER

Not directly in a simple way — Future methods don't expose a Job Id you can query the way Batch or Queueable jobs do. You can only indirectly observe completion through side effects (like checking if a record was updated) or by reviewing the Apex Jobs page in Setup.

🌍 Real World Example (XYZ Company)

When debugging a silent failure in XYZ Company's Future-based notification method, we couldn't query a Job Id directly — we had to rely on Setup's Apex Jobs monitor and debug logs to understand what happened.

🎤 One-Line Answer for Interview

"Future methods don't expose a queryable Job Id — Apex Jobs in Setup and debug logs are your main visibility tools."

Q
Question 010 · Async Apex
Why can't you call a Future method from inside a Batch Apex execute() method?
✅ ANSWER

Batch Apex execute() already runs asynchronously. Salesforce does not allow Future methods to be called from an already-asynchronous context — attempting this throws a runtime exception.

🌍 Real World Example (XYZ Company)

A developer tried calling a Future method for callouts inside XYZ Company's nightly Batch Apex job's execute() method, which failed immediately — we moved the callout logic to use HTTP calls directly within the batch context instead, since Batch Apex itself supports callouts when implementing the right interface.

🎤 One-Line Answer for Interview

"You can't call a Future method from inside Batch Apex's execute() — it's already asynchronous, and Future can't nest inside another async context."

Q
Question 011 · Async Apex
What happens if a Future method throws an unhandled exception?
✅ ANSWER

The exception is logged, but since the Future method runs asynchronously and disconnected from the original transaction, the calling code has no way to catch it directly. The failure typically shows up only in the Apex Jobs page or via debug logs, often going unnoticed without proper error handling and logging built into the method itself.

💻 Proper Error Handling Pattern
@future
public static void processAsync(Set<Id> ids) {
    try {
        // logic here
    } catch (Exception e) {
        // log to a custom Error_Log__c object for visibility
        insert new Error_Log__c(Message__c = e.getMessage());
    }
}
🌍 Real World Example (XYZ Company)

After a silent Future method failure went unnoticed for two days at XYZ Company, we added a try-catch block that logs failures to a custom Error_Log__c object, giving the team genuine visibility into async failures.

🎤 One-Line Answer for Interview

"Unhandled exceptions in Future methods fail silently from the caller's perspective — always build in explicit error logging."

Q
Question 012 · Async Apex
Can a trigger call a Future method directly, and what's a key consideration?
✅ ANSWER

Yes, this is one of the most common Future method use cases. The key consideration is that the trigger should pass only Ids (not full sObjects) and the Future method should re-query fresh data, since trigger context records can't be passed directly as Future parameters.

💻 Trigger Calling a Future Method
trigger AccountTrigger on Account (after insert) {
    Set<Id> accountIds = new Map<Id, Account>(Trigger.new).keySet();
    AccountAsyncHandler.notifyExternalSystem(accountIds);
}
🌍 Real World Example (XYZ Company)

XYZ Company's Account trigger collects newly inserted Account Ids and passes only the Id set to a Future method, which then re-queries the Accounts fresh before making its external callout.

🎤 One-Line Answer for Interview

"Yes — triggers commonly call Future methods, but always pass only Ids, then re-query fresh data inside the Future method itself."

Q
Question 013 · Async Apex
What is the execution order of multiple Future method calls?
✅ ANSWER

Future method execution order is not guaranteed. Salesforce queues them for asynchronous processing, but does not promise they'll run in the exact sequence they were called — this matters significantly if your logic has any dependency on ordering.

🌍 Real World Example (XYZ Company)

XYZ Company initially assumed two Future calls (one updating a record, one sending a notification about that update) would run in the order called — they didn't always, causing notifications referencing stale data. We redesigned to combine both into one Future call.

🎤 One-Line Answer for Interview

"Future method execution order is never guaranteed — never design logic that depends on one Future call finishing before another starts."

Q
Question 014 · Async Apex
Why might a Future method not run as expected in a test class without specific handling?
✅ ANSWER

Future methods don't execute synchronously during a test unless you explicitly wrap the calling code between Test.startTest() and Test.stopTest() — Test.stopTest() forces all queued asynchronous Apex (Future, Queueable, Batch) to run before the test continues.

💻 Testing a Future Method
@isTest
static void testFutureMethod() {
    Test.startTest();
    MyAsyncClass.doAsyncWork(new Set<Id>{testAccountId});
    Test.stopTest(); // forces Future method to execute here
    Account updated = [SELECT Status__c FROM Account WHERE Id = :testAccountId];
    System.assertEquals('Processed', updated.Status__c);
}
🌍 Real World Example (XYZ Company)

Our test for XYZ Company's Future-based status updater initially failed because we forgot Test.stopTest() — the assertion ran before the Future method ever actually executed.

🎤 One-Line Answer for Interview

"Always wrap Future method calls with Test.startTest()/Test.stopTest() in tests — stopTest() is what actually forces the async code to run."

Q
Question 015 · Async Apex
What's the difference between a Future method and Queueable Apex?
✅ ANSWER

Future methods are simpler but more limited — they only accept primitive parameters, can't be chained, and offer no job monitoring. Queueable Apex accepts complex object parameters (including sObjects), supports genuine job chaining, and exposes a Job Id you can monitor via AsyncApexJob.

🌍 Real World Example (XYZ Company)

When XYZ Company needed to chain three sequential async steps for a data migration process, Future methods genuinely couldn't do it — we used Queueable Apex specifically because chaining was a hard requirement.

🎤 One-Line Answer for Interview

"Queueable supports complex parameters, chaining, and job monitoring; Future methods are simpler but more limited on all three fronts."

Q
Question 016 · Async Apex
Can you pass a List as a parameter to a Future method?
✅ ANSWER

Yes, as long as the List contains primitive types (like List<String> or List<Id>) or collections of primitives. You cannot pass a List of sObjects directly.

💻 Valid List Parameter
@future
public static void bulkProcess(List<String> recordIdStrings) {
    // process the list of Id strings
}
🌍 Real World Example (XYZ Company)

XYZ Company's bulk discount-approval Future method accepts a List<Id> of Opportunity Ids, allowing one Future call to handle an entire batch of records instead of one call per record.

🎤 One-Line Answer for Interview

"Yes, but only Lists of primitives — never a List of sObjects directly as a Future method parameter."

Q
Question 017 · Async Apex
What happens to a Future method's job if the org hits its daily async Apex limit?
✅ ANSWER

If the org exceeds its daily limit for asynchronous Apex executions, additional Future method calls will fail to be queued, typically throwing a LimitException at the point the @future call is made.

🌍 Real World Example (XYZ Company)

During a high-volume month-end process, XYZ Company hit the org's daily async limit, causing new Future calls to fail outright — we had to redesign the process to use Batch Apex, which handles large volumes more efficiently within the same governor framework.

🎤 One-Line Answer for Interview

"Hitting the daily async Apex limit causes new Future calls to throw a LimitException — high-volume scenarios usually call for Batch Apex instead."

Q
Question 018 · Async Apex
When should you NOT use a Future method?
✅ ANSWER

Avoid Future methods when you need: genuine job chaining (use Queueable instead), processing very large data volumes with governor-limit resets per chunk (use Batch Apex instead), or precise scheduled timing (use Scheduled Apex instead). Future is best reserved for simple, fire-and-forget async tasks like a single callout.

🌍 Real World Example (XYZ Company)

XYZ Company initially tried using a Future method to process 50,000 records nightly, hit governor limits immediately, and migrated to Batch Apex, which is specifically designed to reset limits across smaller chunks.

🎤 One-Line Answer for Interview

"Avoid Future methods for chaining, large data volumes, or precise scheduling — each of those has a genuinely better-suited async tool."

Category 2: Queueable Apex (20 Questions)
Q
Question 019 · Async Apex
What is Queueable Apex and how does it differ from Future methods?
✅ ANSWER

Queueable Apex is a more powerful asynchronous tool that supports complex object parameters, genuine job chaining, and job monitoring via a Job Id — capabilities Future methods genuinely lack.

💻 Basic Queueable Class
public class ProcessOpportunities implements Queueable {
    public void execute(QueueableContext context) {
        // async logic here
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company replaced an aging Future-based discount notification system with Queueable Apex specifically to gain job chaining and proper monitoring, which the old Future approach never supported.

🎤 One-Line Answer for Interview

"Queueable supports complex parameters, chaining, and monitoring — genuinely more capable than Future methods."

Q
Question 020 · Async Apex
What interface must a class implement to be Queueable?
✅ ANSWER

The class must implement the Queueable interface, which requires defining a single execute method.

💻 Implementing Queueable
public class MyQueueableJob implements Queueable {
    public void execute(QueueableContext context) {
        // logic
    }
}
🌍 Real World Example (XYZ Company)

Every async job in XYZ Company's order processing pipeline implements Queueable as the standard pattern across the team.

🎤 One-Line Answer for Interview

"Implement the Queueable interface and define its single required execute method."

Q
Question 021 · Async Apex
What is the signature of the execute method in Queueable?
✅ ANSWER

public void execute(QueueableContext context) — it must be public, return void, and accept a single QueueableContext parameter.

💻 Exact Signature
public void execute(QueueableContext context) {
    // your async logic
}
🌍 Real World Example (XYZ Company)

A code review at XYZ Company caught a developer who'd accidentally omitted the QueueableContext parameter, causing an immediate compile error before it ever reached production.

🎤 One-Line Answer for Interview

"public void execute(QueueableContext context) — exact required signature, no variations."

Q
Question 022 · Async Apex
How do you enqueue a Queueable job?
✅ ANSWER

Instantiate the class and pass it to System.enqueueJob(), which returns the Job Id as a String.

💻 Enqueuing a Job
ProcessOpportunities job = new ProcessOpportunities();
Id jobId = System.enqueueJob(job);
🌍 Real World Example (XYZ Company)

XYZ Company's Opportunity trigger enqueues a Queueable job and stores the returned Job Id in a custom field for later status tracking.

🎤 One-Line Answer for Interview

"System.enqueueJob(new YourClass()) — returns a Job Id you can use for tracking."

Q
Question 023 · Async Apex
What does 'job chaining' mean in Queueable Apex?
✅ ANSWER

Chaining means calling System.enqueueJob() again from inside the execute method of a currently-running Queueable job, effectively starting a new job once the current one finishes — enabling genuine sequential multi-step async processing.

💻 Chaining Pattern
public class StepOneJob implements Queueable {
    public void execute(QueueableContext context) {
        // do step one work
        System.enqueueJob(new StepTwoJob()); // chain to next job
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company's three-step data migration (validate, transform, load) uses chained Queueable jobs, where each step enqueues the next only after successfully completing its own work.

🎤 One-Line Answer for Interview

"Chaining means enqueueing a new Queueable job from inside another job's execute method — enabling genuine sequential async steps."

Q
Question 024 · Async Apex
What is the maximum chain depth for Queueable jobs?
✅ ANSWER

In most orgs, you can chain up to 5 jobs deep in a single chain sequence. (Unlimited chaining is available in specific contexts, but the standard practical limit to know for interviews is 5.)

🌍 Real World Example (XYZ Company)

XYZ Company's original 7-step chained migration design had to be consolidated into fewer, more substantial steps after hitting the practical chain depth consideration during testing.

🎤 One-Line Answer for Interview

"5 chained jobs deep is the standard practical limit most interviews expect you to know."

Q
Question 025 · Async Apex
Can Queueable Apex accept non-primitive (sObject, custom object) parameters? Why is this an advantage over Future?
✅ ANSWER

Yes — since Queueable is implemented as a class (not a static method), you can pass any data, including full sObjects and custom objects, directly into the constructor. This avoids the re-query step Future methods require.

💻 Passing Complex Objects
public class ProcessAccounts implements Queueable {
    private List<Account> accountsToProcess;
    public ProcessAccounts(List<Account> accounts) {
        this.accountsToProcess = accounts;
    }
    public void execute(QueueableContext context) {
        // use accountsToProcess directly, no re-query needed
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company's Queueable job receives full Account records directly through its constructor, eliminating an unnecessary re-query that the old Future-based version required.

🎤 One-Line Answer for Interview

"Yes — Queueable's constructor can accept full sObjects directly, unlike Future methods which require re-querying."

Q
Question 026 · Async Apex
How do you make a Queueable job perform a callout?
✅ ANSWER

Implement Database.AllowsCallouts alongside Queueable on the class declaration.

💻 Queueable With Callout Support
public class SyncToExternalAPI implements Queueable, Database.AllowsCallouts {
    public void execute(QueueableContext context) {
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://api.xyzcompany.com/sync');
        req.setMethod('POST');
        Http http = new Http();
        http.send(req);
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company's Queueable job syncing Opportunity data to an external system implements both Queueable and Database.AllowsCallouts on the class declaration.

🎤 One-Line Answer for Interview

"Implement Database.AllowsCallouts alongside Queueable — without it, any callout attempt throws an exception."

Q
Question 027 · Async Apex
What interface do you implement alongside Queueable to support callouts?
✅ ANSWER

Database.AllowsCallouts — this is added to the class declaration's implements clause, alongside Queueable itself.

🌍 Real World Example (XYZ Company)

A failed callout in XYZ Company's integration job traced back to a missing Database.AllowsCallouts declaration — adding it immediately fixed the issue.

🎤 One-Line Answer for Interview

"Database.AllowsCallouts, added alongside Queueable in the class's implements clause."

Q
Question 028 · Async Apex
What is the daily governor limit on Queueable jobs?
✅ ANSWER

An org can enqueue up to 50 Queueable jobs per 24-hour period via System.enqueueJob() from synchronous Apex (this is a shared limit with Future method calls in some contexts) — but specifically within a single transaction, the synchronous limit is also a key consideration.

🌍 Real World Example (XYZ Company)

XYZ Company hit unexpected throttling during a high-volume batch trigger that tried enqueueing many individual Queueable jobs — we redesigned to enqueue one job processing a full collection instead.

🎤 One-Line Answer for Interview

"There's a meaningful daily limit on enqueued Queueable jobs — always bulkify rather than enqueueing one job per record."

Q
Question 029 · Async Apex
Can you monitor a Queueable job's status?
✅ ANSWER

Yes — the Job Id returned by System.enqueueJob() can be used to query the AsyncApexJob object, which exposes fields like Status, JobType, NumberOfErrors, and CompletedDate.

💻 Querying Job Status
Id jobId = System.enqueueJob(new MyQueueableJob());
AsyncApexJob job = [SELECT Status, NumberOfErrors 
                    FROM AsyncApexJob WHERE Id = :jobId];
🌍 Real World Example (XYZ Company)

XYZ Company's admin dashboard queries AsyncApexJob using stored Job Ids to show real-time status of in-progress data sync jobs to the operations team.

🎤 One-Line Answer for Interview

"Yes — query AsyncApexJob using the returned Job Id to check Status, NumberOfErrors, and completion details."

Q
Question 030 · Async Apex
What object can you query to check Queueable/Async Apex job status?
✅ ANSWER

AsyncApexJob — this single object tracks status for Future methods, Queueable jobs, Batch Apex jobs, and Scheduled Apex jobs alike.

🌍 Real World Example (XYZ Company)

XYZ Company built a unified "Async Job Monitor" admin page that queries AsyncApexJob across all four async types in one consolidated view.

🎤 One-Line Answer for Interview

"AsyncApexJob — the single object that tracks status across all four async Apex types."

Q
Question 031 · Async Apex
How does Queueable Apex differ from Batch Apex in terms of scale?
✅ ANSWER

Queueable Apex runs as a single execution with standard governor limits applied once — it's meant for moderate-sized async work. Batch Apex splits processing into multiple smaller chunks, with governor limits resetting for each chunk, making it suited for genuinely large data volumes (millions of records).

🌍 Real World Example (XYZ Company)

XYZ Company used Queueable for a few thousand-record reconciliation job, but switched to Batch Apex entirely for their 2-million-record annual data cleanup, since Queueable's single-execution limits weren't sufficient.

🎤 One-Line Answer for Interview

"Queueable suits moderate-sized work in one execution; Batch Apex scales to millions of records by resetting limits per chunk."

Q
Question 032 · Async Apex
What happens if a Queueable job throws an exception?
✅ ANSWER

Like Future methods, an unhandled exception in a Queueable job's execute method fails silently from the caller's perspective. The failure is visible via AsyncApexJob's NumberOfErrors field or debug logs, but proper try-catch error handling and logging should be built into the execute method itself.

💻 Error Handling Pattern
public void execute(QueueableContext context) {
    try {
        // logic
    } catch (Exception e) {
        insert new Error_Log__c(Message__c = e.getMessage());
    }
}
🌍 Real World Example (XYZ Company)

After a silent Queueable failure went unnoticed at XYZ Company, the team added explicit try-catch logging to every Queueable execute method going forward, as a standard team practice.

🎤 One-Line Answer for Interview

"Unhandled exceptions fail silently from the caller's view — check AsyncApexJob.NumberOfErrors or build in explicit logging."

Q
Question 033 · Async Apex
Can you call a Queueable job from a trigger?
✅ ANSWER

Yes, this is a common pattern — but be mindful of bulk trigger context, ensuring you enqueue ONE Queueable job handling a full collection of records, not one job per individual record.

💻 Trigger Calling Queueable
trigger OpportunityTrigger on Opportunity (after update) {
    System.enqueueJob(new ProcessOpportunities(Trigger.new));
}
🌍 Real World Example (XYZ Company)

XYZ Company's Opportunity trigger enqueues a single Queueable job passing the entire Trigger.new collection, correctly handling bulk updates in one job rather than many.

🎤 One-Line Answer for Interview

"Yes, but always enqueue one job for the full record collection — never one job per individual record in a trigger."

Q
Question 034 · Async Apex
What is a common real-world use case for chaining Queueable jobs?
✅ ANSWER

Multi-step data processing pipelines where each step genuinely depends on the previous step completing successfully — like validate, then transform, then load, in a data migration or integration scenario.

🌍 Real World Example (XYZ Company)

XYZ Company's customer data enrichment pipeline chains three Queueable jobs: first validating incoming data, then calling an external enrichment API, then finally updating the Salesforce records with enriched data.

🎤 One-Line Answer for Interview

"Sequential multi-step pipelines (validate → transform → load) are the classic real-world chaining use case."

Q
Question 035 · Async Apex
How do you test a Queueable class in a test method?
✅ ANSWER

Wrap the enqueueJob call between Test.startTest() and Test.stopTest() — exactly like Future methods, Test.stopTest() forces the queued job to actually execute before the test continues.

💻 Testing a Queueable Class
@isTest
static void testQueueableJob() {
    Test.startTest();
    System.enqueueJob(new ProcessOpportunities(testOpps));
    Test.stopTest();
    Opportunity updated = [SELECT Status__c FROM Opportunity WHERE Id = :testOppId];
    System.assertEquals('Processed', updated.Status__c);
}
🌍 Real World Example (XYZ Company)

XYZ Company's test suite for the Queueable discount processor wraps the enqueue call in Test.startTest()/stopTest(), confirming the job actually ran before asserting on its results.

🎤 One-Line Answer for Interview

"Test.startTest()/Test.stopTest() around the enqueueJob call — stopTest() is what forces the job to actually run in tests."

Q
Question 036 · Async Apex
What's the relationship between Queueable Apex and the Transaction Finalizer feature?
✅ ANSWER

A Finalizer is a special callback that runs after a Queueable job completes, whether it succeeds or fails — giving you a guaranteed way to perform cleanup or follow-up actions regardless of outcome. Finalizers are specifically a Queueable-only feature.

💻 Attaching a Finalizer
public void execute(QueueableContext context) {
    System.attachFinalizer(new MyFinalizer());
    // main job logic
}
🌍 Real World Example (XYZ Company)

XYZ Company attaches a Finalizer to their critical billing-sync Queueable job specifically to send an alert notification if the job fails, ensuring failures are never silently missed.

🎤 One-Line Answer for Interview

"Finalizers are a Queueable-exclusive feature providing guaranteed post-execution cleanup or follow-up logic, success or failure."

Q
Question 037 · Async Apex
Why might you choose Queueable over Batch Apex for smaller record sets?
✅ ANSWER

Queueable Apex has less overhead and a simpler single-method interface compared to Batch Apex's three-method structure, making it a better fit when you genuinely don't need Batch's chunk-based processing for smaller, moderate-sized workloads.

🌍 Real World Example (XYZ Company)

XYZ Company's nightly job processing roughly 500 records uses Queueable rather than Batch Apex, since the volume doesn't genuinely require Batch's chunking — simpler code with equivalent results.

🎤 One-Line Answer for Interview

"For smaller, moderate workloads, Queueable's simpler single-method structure is genuinely sufficient — Batch Apex's complexity isn't always necessary."

Q
Question 038 · Async Apex
Can a Queueable job be scheduled to run in the future like Scheduled Apex?
✅ ANSWER

Yes — System.enqueueJob() has an overload that accepts a minimum delay in minutes, allowing you to schedule a Queueable job to run after a specified delay, distinct from full Scheduled Apex's CRON-based recurring scheduling.

💻 Delayed Queueable Execution
// Run after a minimum 10-minute delay
System.enqueueJob(new MyQueueableJob(), 10);
🌍 Real World Example (XYZ Company)

XYZ Company delays a follow-up Queueable reminder job by 30 minutes after an initial customer action, using the delayed enqueueJob overload rather than building full Scheduled Apex for this one-time delay.

🎤 One-Line Answer for Interview

"Yes — System.enqueueJob() supports a minimum-delay-in-minutes overload for one-time delayed execution, distinct from recurring Scheduled Apex."

Category 3: Batch Apex — The Deep Dive (30 Questions)
Q
Question 039 · Async Apex
What is Batch Apex and when should you use it?
✅ ANSWER

Batch Apex processes large numbers of records (thousands to millions) by splitting them into smaller chunks, with governor limits resetting for each chunk. Use it specifically when a job's data volume would otherwise exceed standard transaction limits in a single execution.

💻 Basic Batch Apex Structure
global class CleanupOldRecords implements Database.Batchable<sObject> {
    global Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator('SELECT Id FROM Lead WHERE IsConverted = false AND CreatedDate < LAST_N_DAYS:365');
    }
    global void execute(Database.BatchableContext bc, List<sObject> scope) {
        delete scope;
    }
    global void finish(Database.BatchableContext bc) {
        // post-processing
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company runs a nightly Batch Apex job cleaning up over 200,000 stale, unconverted Leads older than a year — far beyond what a single synchronous transaction could safely handle.

🎤 One-Line Answer for Interview

"Batch Apex processes large data volumes in chunks, resetting governor limits per chunk — use it whenever data volume would exceed single-transaction limits."

Q
Question 040 · Async Apex
What interface must a Batch Apex class implement?
✅ ANSWER

Database.Batchable<sObject> — and the class declaration itself must use the global access modifier.

💻 Interface Declaration
global class MyBatchClass implements Database.Batchable<sObject> {
    // three required methods
}
🌍 Real World Example (XYZ Company)

Every Batch Apex class at XYZ Company follows the exact same global class ... implements Database.Batchable<sObject> pattern as a team standard.

🎤 One-Line Answer for Interview

"Database.Batchable<sObject> — and the class itself must be declared global."

Q
Question 041 · Async Apex
What are the three required methods in Database.Batchable?
✅ ANSWER

start, execute, and finish — every Batch Apex class must implement all three, even if one of them (commonly finish) ends up doing very little.

💻 All Three Required Methods
global class MyBatch implements Database.Batchable<sObject> {
    global Database.QueryLocator start(Database.BatchableContext bc) { }
    global void execute(Database.BatchableContext bc, List<sObject> scope) { }
    global void finish(Database.BatchableContext bc) { }
}
🌍 Real World Example (XYZ Company)

A junior developer at XYZ Company initially forgot to implement finish(), and the class failed to compile until all three required methods were present.

🎤 One-Line Answer for Interview

"start, execute, and finish — all three are mandatory, even if finish does minimal work."

Q
Question 042 · Async Apex
What does the start method do?
✅ ANSWER

It runs once at the very beginning of the job and defines the full set of records to be processed, typically by returning a Database.QueryLocator (or an Iterable).

💻 Start Method Example
global Database.QueryLocator start(Database.BatchableContext bc) {
    return Database.getQueryLocator(
        'SELECT Id, Email FROM Contact WHERE Email = null'
    );
}
🌍 Real World Example (XYZ Company)

XYZ Company's data quality Batch job's start method defines the full set of Contacts missing an email address, which then gets automatically split into chunks for execute.

🎤 One-Line Answer for Interview

"start() runs once, defining the complete record set to process — typically via a QueryLocator."

Q
Question 043 · Async Apex
What does the execute method do, and how many times is it called?
✅ ANSWER

execute() contains the actual processing logic and is called once per chunk — the number of times depends on total record count divided by batch size.

💻 Execute Method Example
global void execute(Database.BatchableContext bc, List<sObject> scope) {
    List<Contact> contacts = (List<Contact>) scope;
    for (Contact c : contacts) {
        c.Email_Missing__c = true;
    }
    update contacts;
}
🌍 Real World Example (XYZ Company)

With 100,000 records and a batch size of 200, XYZ Company's execute method runs 500 separate times, each handling its own 200-record chunk independently.

🎤 One-Line Answer for Interview

"execute() is called once per chunk — with default batch size 200, a 100,000-record job calls execute() 500 times."

Q
Question 044 · Async Apex
What does the finish method do?
✅ ANSWER

finish() runs once at the very end, after all chunks have completed execute(). Commonly used for completion emails, chaining a next Batch job, or logging final statistics.

💻 Finish Method Example
global void finish(Database.BatchableContext bc) {
    AsyncApexJob job = [SELECT Id, Status, NumberOfErrors 
                         FROM AsyncApexJob WHERE Id = :bc.getJobId()];
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    mail.setSubject('Batch Job Complete: ' + job.Status);
    Messaging.sendEmail(new List<Messaging.SingleEmailMessage>{mail});
}
🌍 Real World Example (XYZ Company)

XYZ Company's finish() method sends a summary email to the Admin team showing total records processed and any errors, every time the nightly cleanup batch completes.

🎤 One-Line Answer for Interview

"finish() runs once after all chunks complete — commonly used for completion emails or chaining the next batch job."

Q
Question 045 · Async Apex
What is the default batch size, and what's the maximum?
✅ ANSWER

The default batch size is 200 records per chunk. The maximum allowed batch size is 2,000 records per chunk.

🌍 Real World Example (XYZ Company)

XYZ Company's simple field-update batch job uses the maximum 2,000 batch size for efficiency, while a more complex batch involving callouts per record uses a much smaller size to stay within callout limits per transaction.

🎤 One-Line Answer for Interview

"Default is 200, maximum is 2,000 — choose based on how much processing each individual chunk needs to do."

Q
Question 046 · Async Apex
How do you specify a custom batch size?
✅ ANSWER

Pass the desired batch size as the second parameter to Database.executeBatch().

💻 Custom Batch Size
MyBatchClass batchJob = new MyBatchClass();
Database.executeBatch(batchJob, 500);
🌍 Real World Example (XYZ Company)

XYZ Company's record cleanup batch explicitly sets a batch size of 500, balancing processing speed against the complexity of each chunk's logic.

🎤 One-Line Answer for Interview

"Database.executeBatch(yourBatchInstance, customSize) — the second parameter sets your batch size."

Q
Question 047 · Async Apex
What is the difference between QueryLocator and Iterable in the start method?
✅ ANSWER

Database.QueryLocator handles up to 50 million records via a SOQL query. A custom Iterable is used when the record set requires custom logic beyond a simple query, but is limited to a much smaller record count.

💻 Custom Iterable Example
global Iterable<Account> start(Database.BatchableContext bc) {
    return new MyCustomAccountIterator();
}
🌍 Real World Example (XYZ Company)

XYZ Company uses QueryLocator for the vast majority of batch jobs, but used a custom Iterable once for a complex scenario requiring records generated from an external API response rather than a direct query.

🎤 One-Line Answer for Interview

"QueryLocator handles up to 50 million records via SOQL; custom Iterable is for custom-generated record sets with a much lower ceiling."

Q
Question 048 · Async Apex
When would you use Iterable instead of QueryLocator in start?
✅ ANSWER

When your record set genuinely cannot be defined by a simple SOQL query — for example, records derived from a calculation, an external data source, or complex custom logic a single query can't express.

🌍 Real World Example (XYZ Company)

XYZ Company needed to batch-process a custom-calculated list of "at-risk" Accounts based on logic too complex for a single SOQL WHERE clause, so a custom Iterable built that list programmatically instead.

🎤 One-Line Answer for Interview

"Use Iterable when your record set requires custom logic beyond what a single SOQL query can express."

Q
Question 049 · Async Apex
How do you invoke/start a Batch Apex job?
✅ ANSWER

Instantiate the batch class and pass it to Database.executeBatch(), optionally with a custom batch size as the second parameter.

💻 Starting a Batch Job
MyBatchClass batchJob = new MyBatchClass();
Id batchJobId = Database.executeBatch(batchJob);
🌍 Real World Example (XYZ Company)

XYZ Company's nightly scheduled job calls Database.executeBatch() to kick off the Lead cleanup batch, storing the returned Job Id for status tracking.

🎤 One-Line Answer for Interview

"Database.executeBatch(new YourBatchClass()) — returns a Job Id you can use for tracking."

Q
Question 050 · Async Apex
What is the maximum number of batch jobs that can be queued/active at once?
✅ ANSWER

An org can have up to 5 Batch Apex jobs queued or actively executing at the same time.

🌍 Real World Example (XYZ Company)

XYZ Company hit this limit during a busy migration weekend when too many batch jobs were triggered simultaneously — subsequent Database.executeBatch() calls failed until earlier jobs completed.

🎤 One-Line Answer for Interview

"5 queued or active Batch jobs is the org-wide limit at any given moment."

Q
Question 051 · Async Apex
What does Database.Stateful do, and why would you use it?
✅ ANSWER

Implementing the Database.Stateful marker interface allows instance member variables to retain their values ACROSS multiple execute() calls — by default, Batch Apex is stateless, meaning variables reset between chunks.

💻 Stateful Batch Example
global class CountingBatch implements Database.Batchable<sObject>, Database.Stateful {
    global Integer totalProcessed = 0;
    global void execute(Database.BatchableContext bc, List<sObject> scope) {
        totalProcessed += scope.size();
    }
    global void finish(Database.BatchableContext bc) {
        System.debug('Total processed: ' + totalProcessed);
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company's data migration batch uses Database.Stateful to maintain a running count of successfully migrated records across all chunks, reporting the final total in finish().

🎤 One-Line Answer for Interview

"Database.Stateful keeps instance variables persistent across chunks — without it, variables reset to their initial value on every execute() call."

Q
Question 052 · Async Apex
By default, is a Batch Apex class stateful or stateless across batches?
✅ ANSWER

Stateless. Instance variables reset to their initial values at the start of every single execute() call unless Database.Stateful is explicitly implemented.

🌍 Real World Example (XYZ Company)

A developer at XYZ Company was confused why a running total kept resetting to zero in every chunk — the class wasn't marked Database.Stateful, so the variable reinitialized every execute() call as expected default behavior.

🎤 One-Line Answer for Interview

"Stateless by default — Database.Stateful must be explicitly added to retain variable values across chunks."

Q
Question 053 · Async Apex
How do you track the status of a running Batch job?
✅ ANSWER

Query the AsyncApexJob object using the Job Id returned by Database.executeBatch(), checking fields like Status, JobItemsProcessed, TotalJobItems, and NumberOfErrors.

💻 Checking Batch Job Status
Id jobId = Database.executeBatch(new MyBatchClass());
AsyncApexJob job = [SELECT Status, JobItemsProcessed, TotalJobItems, NumberOfErrors
                     FROM AsyncApexJob WHERE Id = :jobId];
🌍 Real World Example (XYZ Company)

XYZ Company's Admin dashboard polls AsyncApexJob using stored Job Ids, showing operations staff real-time progress on long-running nightly batch jobs.

🎤 One-Line Answer for Interview

"Query AsyncApexJob with the returned Job Id — Status, JobItemsProcessed, and TotalJobItems give genuine progress visibility."

Q
Question 054 · Async Apex
What object would you query to check batch job progress?
✅ ANSWER

AsyncApexJob — with Batch-specific fields like TotalJobItems and JobItemsProcessed giving genuine chunk-level progress.

🌍 Real World Example (XYZ Company)

XYZ Company's monitoring tool uses AsyncApexJob's JobItemsProcessed/TotalJobItems ratio to calculate and display a genuine percentage-complete progress bar for active batch jobs.

🎤 One-Line Answer for Interview

"AsyncApexJob — with JobItemsProcessed and TotalJobItems giving genuine, calculable progress percentage."

Q
Question 055 · Async Apex
Can you chain one Batch Apex job to run another from finish()?
✅ ANSWER

Yes — calling Database.executeBatch() for a second batch class from inside the first batch's finish() method is the standard correct pattern for chaining sequential batch jobs.

💻 Chaining Batch Jobs
global void finish(Database.BatchableContext bc) {
    Database.executeBatch(new SecondBatchClass());
}
🌍 Real World Example (XYZ Company)

XYZ Company chains a validation batch into a cleanup batch — finish() on the validation job automatically kicks off the cleanup job for any records flagged as invalid.

🎤 One-Line Answer for Interview

"Yes — calling Database.executeBatch() for the next class from inside finish() is the standard batch-chaining pattern."

Q
Question 056 · Async Apex
What governor limits reset with each batch execute call?
✅ ANSWER

Most per-transaction governor limits reset with each execute() call — including SOQL query rows (50,000), DML statements (150), and CPU time — since each execute() call is treated as its own discrete transaction.

🌍 Real World Example (XYZ Company)

XYZ Company's batch job processing complex records with multiple related-object lookups relies specifically on this per-chunk limit reset, which would be impossible to achieve in a single massive synchronous transaction.

🎤 One-Line Answer for Interview

"Most per-transaction limits (SOQL rows, DML statements, CPU time) reset with every execute() call — each chunk is its own fresh transaction."

Q
Question 057 · Async Apex
How do you handle errors within a single batch execute() without failing the whole job?
✅ ANSWER

Use Database DML methods with the allOrNone parameter set to false (e.g., Database.update(records, false)), which allows individual record failures within a chunk without halting the entire chunk or job.

💻 Partial Success Pattern
global void execute(Database.BatchableContext bc, List<sObject> scope) {
    List<Database.SaveResult> results = Database.update(scope, false);
    for (Database.SaveResult sr : results) {
        if (!sr.isSuccess()) {
            // log the specific failure
        }
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company's batch update job uses Database.update(records, false) so that one record failing validation doesn't stop the other 199 records in that chunk from successfully updating.

🎤 One-Line Answer for Interview

"Database.update(records, false) — partial success mode lets individual record failures not halt the whole chunk or job."

Q
Question 058 · Async Apex
What is Database.executeBatch() and what parameters does it accept?
✅ ANSWER

It's the method that starts a Batch Apex job. It accepts the batch class instance as the first (required) parameter, and an optional second parameter for custom batch size.

💻 Full Signature
Database.executeBatch(Database.Batchable<sObject> instance, Integer batchSize)
🌍 Real World Example (XYZ Company)

XYZ Company always explicitly specifies a batch size as the second parameter, making the team's intent clear in code reviews.

🎤 One-Line Answer for Interview

"Database.executeBatch(batchInstance, optionalBatchSize) — starts the job and returns its Job Id."

Q
Question 059 · Async Apex
Can Batch Apex be scheduled to run periodically? How?
✅ ANSWER

Yes — by writing a separate Scheduled Apex class (implementing Schedulable) whose execute method calls Database.executeBatch(), then scheduling that class via System.schedule().

💻 Scheduling a Batch Job
global class ScheduledBatchRunner implements Schedulable {
    global void execute(SchedulableContext sc) {
        Database.executeBatch(new MyBatchClass());
    }
}
// System.schedule('Nightly Cleanup', '0 0 2 * * ?', new ScheduledBatchRunner());
🌍 Real World Example (XYZ Company)

XYZ Company's nightly 2 AM cleanup combines Scheduled Apex (for timing) with Batch Apex (for the actual large-scale processing) — exactly this two-class pattern.

🎤 One-Line Answer for Interview

"Write a Schedulable class whose execute() calls Database.executeBatch() — Scheduled Apex handles timing, Batch Apex handles processing."

Q
Question 060 · Async Apex
What's the maximum number of Batch jobs that can be submitted in a single day?
✅ ANSWER

Up to 250,000 batch Apex executions per rolling 24-hour period — distinct from the 5-concurrent-job limit.

🌍 Real World Example (XYZ Company)

XYZ Company's high-volume batch operations have never come close to this daily ceiling — the 5-concurrent-job limit is almost always the more practically relevant constraint.

🎤 One-Line Answer for Interview

"250,000 batch executions per day is the generous daily ceiling — the 5-concurrent-job limit is usually the more practical constraint."

Q
Question 061 · Async Apex
Why might you choose Batch Apex over a Queueable for a million-record data cleanup?
✅ ANSWER

Queueable Apex executes as a single transaction — it genuinely cannot handle a million records without hitting SOQL or DML limits. Batch Apex's chunk-based processing with limits resetting per chunk is specifically designed for exactly this scale.

🌍 Real World Example (XYZ Company)

XYZ Company's annual million-record archive cleanup uses Batch Apex specifically because Queueable's single-transaction limits would be hit almost immediately at that scale.

🎤 One-Line Answer for Interview

"At million-record scale, Queueable's single-transaction limits are insufficient — Batch Apex's per-chunk limit reset is specifically built for this."

Q
Question 062 · Async Apex
What is a common mistake when querying related/child records inside execute()?
✅ ANSWER

Querying child/related records individually inside a loop within execute() quickly hits the 100-query-per-transaction limit. Always use a single bulk query for all related records across the entire chunk at once, then match them in memory.

💻 Correct Bulk Query Pattern
global void execute(Database.BatchableContext bc, List<sObject> scope) {
    Set<Id> accountIds = new Map<Id, Account>((List<Account>)scope).keySet();
    Map<Id, List<Contact>> contactsByAccount = new Map<Id, List<Contact>>();
    for (Contact c : [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountIds]) {
        if (!contactsByAccount.containsKey(c.AccountId)) {
            contactsByAccount.put(c.AccountId, new List<Contact>());
        }
        contactsByAccount.get(c.AccountId).add(c);
    }
}
🌍 Real World Example (XYZ Company)

A junior developer at XYZ Company initially queried related Contacts inside a per-Account loop, hitting SOQL limits at scale — the fix was a single bulk query for the whole chunk.

🎤 One-Line Answer for Interview

"Never query inside a loop, even within a single execute() chunk — always bulk-query once for the entire chunk."

Q
Question 063 · Async Apex
How do you abort a running Batch Apex job?
✅ ANSWER

Call System.abortJob() with the Job Id, or manually abort it through Setup's Apex Jobs page.

💻 Aborting Programmatically
System.abortJob(batchJobId);
🌍 Real World Example (XYZ Company)

When XYZ Company discovered a batch job processing the wrong record set, an Admin immediately aborted it via Setup's Apex Jobs page rather than letting it complete and cause further data issues.

🎤 One-Line Answer for Interview

"System.abortJob(jobId) programmatically, or manually through Setup's Apex Jobs page."

Q
Question 064 · Async Apex
What's the difference between Batch Apex and a Scheduled Apex job that calls Batch Apex?
✅ ANSWER

Batch Apex alone runs once, immediately when invoked. Scheduled Apex adds recurring, time-based triggering via CRON expressions — combining them means a Schedulable class's execute() calls Database.executeBatch() on a recurring schedule.

🌍 Real World Example (XYZ Company)

XYZ Company's batch cleanup class itself has no built-in recurrence — a separate Scheduled Apex class is what makes it run automatically every night at 2 AM.

🎤 One-Line Answer for Interview

"Batch Apex alone runs once when called; Scheduled Apex adds the recurring trigger that calls it automatically on a schedule."

Q
Question 065 · Async Apex
Can you call a Future method from inside Batch Apex execute()? Why or why not?
✅ ANSWER

No. Batch Apex execute() is already running asynchronously, and Salesforce doesn't allow Future methods to be called from an already-asynchronous context.

🌍 Real World Example (XYZ Company)

A developer tried calling a Future method for an external callout from inside XYZ Company's batch execute() — it failed immediately. Implementing Database.AllowsCallouts on the batch class was the correct fix instead.

🎤 One-Line Answer for Interview

"No — implement Database.AllowsCallouts on the batch class instead if you need callouts from execute()."

Q
Question 066 · Async Apex
What happens to a Batch job if execute() throws an unhandled exception in one batch?
✅ ANSWER

That specific chunk fails and its changes roll back, but other chunks that have already completed are NOT automatically rolled back — each execute() call is its own separate transaction.

🌍 Real World Example (XYZ Company)

When one problematic chunk caused an unhandled exception in XYZ Company's batch job, only that specific 200-record chunk failed — the other 499 chunks completed successfully.

🎤 One-Line Answer for Interview

"Each chunk is its own independent transaction — one chunk's failure doesn't roll back other already-completed chunks."

Q
Question 067 · Async Apex
How would you test a Batch Apex class properly, including asserting on results?
✅ ANSWER

Wrap the Database.executeBatch() call between Test.startTest() and Test.stopTest(), which forces the batch job to fully execute synchronously within the test context, then query and assert on the actual resulting data.

💻 Complete Batch Apex Test
@isTest
static void testBatchCleanup() {
    insert testLeads;
    Test.startTest();
    Database.executeBatch(new CleanupOldRecords());
    Test.stopTest();
    List<Lead> remaining = [SELECT Id FROM Lead WHERE Id IN :testLeads];
    System.assertEquals(0, remaining.size(), 'Old leads should be deleted');
}
🌍 Real World Example (XYZ Company)

XYZ Company's batch test suite always wraps executeBatch() in Test.startTest()/stopTest(), then re-queries and asserts on actual data state afterward.

🎤 One-Line Answer for Interview

"Test.startTest()/Test.stopTest() around executeBatch() forces full synchronous completion — then query and assert on actual resulting data."

Q
Question 068 · Async Apex
What's a genuine real-world Batch Apex use case with a bulk data cleanup pattern?
✅ ANSWER

A nightly job that identifies and archives old Closed Lost Opportunities, stale unconverted Leads, or expired temporary records — anything where data volume is large enough that a scheduled flow or simple automation would hit governor limits.

💻 Complete Cleanup Pattern
global class ArchiveStaleOpportunities implements Database.Batchable<sObject> {
    global Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator(
            'SELECT Id FROM Opportunity WHERE StageName = \'Closed Lost\' AND LastModifiedDate < LAST_N_DAYS:730'
        );
    }
    global void execute(Database.BatchableContext bc, List<sObject> scope) {
        for (Opportunity o : (List<Opportunity>) scope) {
            o.Archived__c = true;
        }
        update (List<Opportunity>) scope;
    }
    global void finish(Database.BatchableContext bc) { }
}
🌍 Real World Example (XYZ Company)

XYZ Company runs this exact pattern nightly, archiving Closed Lost Opportunities older than two years, keeping the active pipeline clean without permanently deleting historical data.

🎤 One-Line Answer for Interview

"Archiving stale records at large volume (old Leads, Closed Lost Opps, expired temp data) is the classic real-world Batch Apex use case."

Category 4: Scheduled Apex (17 Questions)
Q
Question 069 · Async Apex
What is Scheduled Apex and what interface does it require?
✅ ANSWER

Scheduled Apex runs Apex code automatically at specified recurring times, similar to a cron job. It requires implementing the Schedulable interface.

💻 Basic Schedulable Class
global class NightlyCleanup implements Schedulable {
    global void execute(SchedulableContext sc) {
        // logic to run on schedule
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company's nightly data quality check implements Schedulable, running automatically every night without any manual trigger needed.

🎤 One-Line Answer for Interview

"Scheduled Apex automates recurring execution by implementing the Schedulable interface."

Q
Question 070 · Async Apex
What is the signature of the execute method in Schedulable?
✅ ANSWER

global void execute(SchedulableContext sc) — public/global, returns void, accepts a single SchedulableContext parameter.

💻 Exact Signature
global void execute(SchedulableContext sc) {
    // scheduled logic here
}
🌍 Real World Example (XYZ Company)

Every Scheduled Apex class at XYZ Company follows this exact signature as a team standard.

🎤 One-Line Answer for Interview

"global void execute(SchedulableContext sc) — exact required signature."

Q
Question 071 · Async Apex
How do you schedule an Apex class to run, using System.schedule?
✅ ANSWER

Call System.schedule(), passing a job name, a CRON expression string, and an instance of your Schedulable class.

💻 Scheduling a Job
String cronExpression = '0 0 2 * * ?'; // every day at 2 AM
System.schedule('Nightly Cleanup Job', cronExpression, new NightlyCleanup());
🌍 Real World Example (XYZ Company)

XYZ Company's Admin scheduled the nightly cleanup job to run at 2 AM using System.schedule(), executed once from Developer Console to set up the recurring job.

🎤 One-Line Answer for Interview

"System.schedule(jobName, cronExpression, schedulableInstance) — sets up the recurring execution."

Q
Question 072 · Async Apex
What is a CRON expression, and what format does Salesforce use?
✅ ANSWER

A CRON expression defines a recurring schedule. Salesforce uses a 7-field format: Seconds Minutes Hours Day_of_month Month Day_of_week Optional_year.

💻 CRON Expression Examples
'0 0 2 * * ?'         // every day at 2:00 AM
'0 30 9 ? * MON-FRI'  // 9:30 AM, weekdays only
'0 0 0 1 * ?'         // midnight on the 1st of every month
🌍 Real World Example (XYZ Company)

XYZ Company uses '0 0 2 * * ?' for nightly batch kickoffs and '0 30 9 ? * MON-FRI' for weekday-only morning reports.

🎤 One-Line Answer for Interview

"A 7-field CRON expression (Seconds Minutes Hours Day Month DayOfWeek Year) defines exactly when the job runs."

Q
Question 073 · Async Apex
What is the maximum number of scheduled Apex jobs allowed at once?
✅ ANSWER

An org can have up to 100 scheduled Apex jobs active at any given time.

🌍 Real World Example (XYZ Company)

XYZ Company consolidated several narrowly-scoped scheduled jobs into fewer, more comprehensive ones after approaching this limit during a period of rapid automation growth.

🎤 One-Line Answer for Interview

"100 active scheduled jobs is the typical org-wide ceiling."

Q
Question 074 · Async Apex
Can you schedule a class to run Batch Apex inside its execute method?
✅ ANSWER

Yes — this is the standard pattern for running Batch Apex on a recurring schedule. The Schedulable class's execute method simply calls Database.executeBatch().

💻 Scheduled Class Triggering a Batch
global class ScheduledBatchTrigger implements Schedulable {
    global void execute(SchedulableContext sc) {
        Database.executeBatch(new CleanupOldRecords(), 200);
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company's nightly Lead cleanup combines this exact pattern — a Schedulable class scheduled for 2 AM that calls Database.executeBatch() for the actual cleanup logic.

🎤 One-Line Answer for Interview

"Yes — the Schedulable execute() method calling Database.executeBatch() is the standard pattern for scheduling recurring Batch jobs."

Q
Question 075 · Async Apex
How do you view currently scheduled jobs?
✅ ANSWER

Navigate to Setup → Scheduled Jobs, or query the CronTrigger object directly via SOQL/Apex.

💻 Querying Scheduled Jobs
List<CronTrigger> jobs = [SELECT Id, CronJobDetail.Name, NextFireTime 
                           FROM CronTrigger];
🌍 Real World Example (XYZ Company)

XYZ Company's Admin regularly checks Setup's Scheduled Jobs page to confirm the nightly cleanup job's NextFireTime is set correctly after any CRON expression changes.

🎤 One-Line Answer for Interview

"Setup → Scheduled Jobs in the UI, or query the CronTrigger object directly in Apex/SOQL."

Q
Question 076 · Async Apex
How do you abort a Scheduled Apex job?
✅ ANSWER

Call System.abortJob() with the Job Id (obtainable from CronTrigger), or manually abort it from Setup's Scheduled Jobs page.

💻 Aborting a Scheduled Job
System.abortJob(scheduledJobId);
🌍 Real World Example (XYZ Company)

When XYZ Company needed to pause the nightly cleanup during a data migration weekend, an Admin aborted the scheduled job via Setup, then rescheduled it once migration completed.

🎤 One-Line Answer for Interview

"System.abortJob(jobId) programmatically, or manually through Setup's Scheduled Jobs page."

Q
Question 077 · Async Apex
Can Scheduled Apex be scheduled via the UI instead of code?
✅ ANSWER

Yes — Setup includes an 'Apex Classes' page with a 'Schedule Apex' button, letting an Admin configure the schedule through a simpler UI without writing System.schedule() code directly.

🌍 Real World Example (XYZ Company)

XYZ Company's Admin team schedules most recurring jobs through the UI directly, reserving System.schedule() code for cases needing more precise or unusual CRON timing.

🎤 One-Line Answer for Interview

"Yes — Setup's Apex Classes page has a UI-based Schedule Apex option, no code required for standard scheduling needs."

Q
Question 078 · Async Apex
What's the minimum interval between scheduled executions?
✅ ANSWER

Scheduled Apex cannot run more frequently than once every hour through standard System.schedule() patterns — true sub-hourly precision isn't genuinely supported by standard Scheduled Apex.

🌍 Real World Example (XYZ Company)

XYZ Company initially wanted a 15-minute recurring sync job, but Scheduled Apex's practical granularity didn't support that — they redesigned using a Queueable self-rescheduling chain pattern instead.

🎤 One-Line Answer for Interview

"Standard Scheduled Apex doesn't support sub-hourly precision — finer-grained recurring needs typically require a different pattern."

Q
Question 079 · Async Apex
What happens if a scheduled job's execute method throws an exception?
✅ ANSWER

The job execution fails for that occurrence, but the job itself remains scheduled and will attempt to run again at its next scheduled time, unless manually aborted.

🌍 Real World Example (XYZ Company)

When XYZ Company's scheduled job hit an unexpected null reference one night, that single occurrence failed, but the job correctly attempted and succeeded at its next scheduled run the following night.

🎤 One-Line Answer for Interview

"A failed execution doesn't unschedule the job — it remains active and will attempt again at its next scheduled time."

Q
Question 080 · Async Apex
How would you reschedule a job to run again automatically (self-rescheduling pattern)?
✅ ANSWER

Inside the execute method, call System.schedule() again for the same class with a new future CRON time — effectively having the job schedule its own next occurrence.

💻 Self-Rescheduling Pattern
global class SelfReschedulingJob implements Schedulable {
    global void execute(SchedulableContext sc) {
        // do the actual work
        Datetime nextRun = Datetime.now().addMinutes(15);
        String cron = nextRun.second() + ' ' + nextRun.minute() + ' ' + nextRun.hour()
                      + ' ' + nextRun.day() + ' ' + nextRun.month() + ' ? ' + nextRun.year();
        System.schedule('NextRun-' + nextRun, cron, new SelfReschedulingJob());
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company achieves genuine 15-minute interval processing using this self-rescheduling pattern, working around standard Scheduled Apex's hourly-minimum limitation.

🎤 One-Line Answer for Interview

"Self-rescheduling: call System.schedule() again from inside execute() with a new dynamically-calculated future time."

Q
Question 081 · Async Apex
What's the relationship between Scheduled Apex and Batch Apex for very large data jobs?
✅ ANSWER

Scheduled Apex provides the TIMING; Batch Apex provides the SCALE. They're complementary — Scheduled Apex's execute() typically just calls Database.executeBatch() to kick off the actual large-scale processing.

🌍 Real World Example (XYZ Company)

XYZ Company's nightly multi-million-record archive job uses Scheduled Apex for the 2 AM trigger timing, and Batch Apex for the actual chunked processing of millions of records.

🎤 One-Line Answer for Interview

"Scheduled Apex handles timing; Batch Apex handles scale — they're typically combined, not alternatives to each other."

Q
Question 082 · Async Apex
Can a Scheduled Apex job make a callout directly?
✅ ANSWER

No — Scheduled Apex's execute() cannot make synchronous callouts directly. The standard workaround is having execute() enqueue a Queueable job (with Database.AllowsCallouts) to perform the actual callout.

💻 Scheduled Job Delegating to Queueable
global class ScheduledSync implements Schedulable {
    global void execute(SchedulableContext sc) {
        System.enqueueJob(new CalloutQueueable());
    }
}
global class CalloutQueueable implements Queueable, Database.AllowsCallouts {
    global void execute(QueueableContext context) {
        // actual callout logic here
    }
}
🌍 Real World Example (XYZ Company)

XYZ Company's nightly external API sync uses a Scheduled Apex class that enqueues a Queueable job to perform the actual HTTP callout.

🎤 One-Line Answer for Interview

"No, not directly — enqueue a Queueable job (with Database.AllowsCallouts) to actually perform any callout."

Q
Question 083 · Async Apex
How do you test Scheduled Apex in a test class?
✅ ANSWER

Use Test.startTest()/Test.stopTest() around the System.schedule() call, which forces the scheduled execution to run within the test context.

💻 Testing Scheduled Apex
@isTest
static void testScheduledJob() {
    Test.startTest();
    System.schedule('Test Job', '0 0 2 * * ?', new NightlyCleanup());
    Test.stopTest();
    // assert on expected results
}
🌍 Real World Example (XYZ Company)

XYZ Company's test for the nightly cleanup scheduled job wraps the System.schedule() call in Test.startTest()/stopTest(), confirming the execute() logic ran and produced correct results.

🎤 One-Line Answer for Interview

"Test.startTest()/Test.stopTest() around System.schedule() forces the scheduled execute() to actually run within the test."

Q
Question 084 · Async Apex
What System class method lets you get the Job Id when scheduling?
✅ ANSWER

System.schedule() itself returns the Job Id directly as its return value (a String representing the CronTrigger Id).

💻 Capturing the Job Id
String jobId = System.schedule('My Job', '0 0 2 * * ?', new MyScheduledClass());
🌍 Real World Example (XYZ Company)

XYZ Company stores the returned Job Id in a Custom Setting whenever scheduling a new recurring job, making it easy to programmatically reference or abort that job later.

🎤 One-Line Answer for Interview

"System.schedule() returns the Job Id directly — capture it for later reference or abort calls."

Q
Question 085 · Async Apex
What's a genuine real-world use case for Scheduled Apex?
✅ ANSWER

A nightly data quality check that flags incomplete records, a weekly summary report emailed to leadership, or a recurring sync job keeping Salesforce aligned with an external system on a predictable cadence.

🌍 Real World Example (XYZ Company)

XYZ Company's Scheduled Apex job runs every Monday at 6 AM, generating and emailing a weekly pipeline summary report to the VP of Sales before the team's Monday morning meeting.

🎤 One-Line Answer for Interview

"Recurring data quality checks, scheduled reports, or predictable external sync jobs are classic real-world Scheduled Apex use cases."

Category 5: Choosing the Right Tool & Governor Limits (15 Questions)
Q
Question 086 · Async Apex
When would you choose Future over Queueable?
✅ ANSWER

Genuinely rarely in new code — Queueable does everything Future does, plus more. Future mainly persists in legacy codebases or for extremely lightweight fire-and-forget tasks.

🌍 Real World Example (XYZ Company)

XYZ Company's newer codebase exclusively uses Queueable for all new async work, only maintaining a few legacy Future methods inherited from before the team standardized on Queueable.

🎤 One-Line Answer for Interview

"Rarely in new code — Queueable is generally the more capable choice; Future mainly persists in legacy code."

Q
Question 087 · Async Apex
When would you choose Queueable over Batch Apex?
✅ ANSWER

When data volume is moderate and you need chaining or complex object parameters, but don't genuinely need Batch's chunk-based limit resets for massive-scale processing.

🌍 Real World Example (XYZ Company)

XYZ Company's multi-step but moderate-volume order validation pipeline uses chained Queueable jobs rather than Batch Apex, since chaining was the genuine requirement, not raw scale.

🎤 One-Line Answer for Interview

"Choose Queueable when you need chaining or complex parameters at moderate scale, without needing Batch's chunk-based processing."

Q
Question 088 · Async Apex
When would you choose Batch Apex over Queueable?
✅ ANSWER

When data volume is large enough that a single transaction's governor limits would be exceeded — Batch Apex's per-chunk limit reset is specifically designed for million-record-scale processing.

🌍 Real World Example (XYZ Company)

XYZ Company's 3-million-record annual archive job uses Batch Apex because no other async tool could process that volume without hitting governor limits.

🎤 One-Line Answer for Interview

"Choose Batch Apex when data volume would exceed what a single transaction can safely handle."

Q
Question 089 · Async Apex
What is the unified governor limit shared across Future, Queueable, and Batch (daily async Apex limit)?
✅ ANSWER

Most orgs share a combined daily limit of 250,000 asynchronous Apex method executions across Future, Queueable, and Batch executions combined.

🌍 Real World Example (XYZ Company)

XYZ Company monitors their combined daily async execution count via a custom dashboard, ensuring high-volume days don't risk hitting this shared ceiling across all async types combined.

🎤 One-Line Answer for Interview

"250,000 combined daily async executions is shared across Future, Queueable, and Batch — not separate limits per type."

Q
Question 090 · Async Apex
What is AsyncApexJob and what fields does it expose?
✅ ANSWER

AsyncApexJob is the single object Salesforce uses to track all four async Apex types. Key fields: Id, Status, JobType, MethodName, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedDate, CompletedDate.

💻 Querying Key Fields
AsyncApexJob job = [SELECT Status, JobType, NumberOfErrors, 
                            JobItemsProcessed, TotalJobItems
                     FROM AsyncApexJob WHERE Id = :jobId];
🌍 Real World Example (XYZ Company)

XYZ Company's unified "Async Job Monitor" admin tool queries AsyncApexJob across all job types, giving operations staff one consolidated view.

🎤 One-Line Answer for Interview

"AsyncApexJob — Status, JobType, NumberOfErrors, JobItemsProcessed, and TotalJobItems are the key fields for monitoring."

Q
Question 091 · Async Apex
How do all four async types differ in terms of 'real-time-ness'?
✅ ANSWER

None are truly real-time — all queue for async execution with some delay. Future and Queueable tend to execute soonest; Batch has more inherent delay due to chunking overhead; Scheduled Apex executes at its defined CRON time, not immediately upon setup.

🌍 Real World Example (XYZ Company)

XYZ Company learned not to rely on any async Apex type for sub-second processing — for that, they redesigned to use a synchronous, carefully-bulkified approach instead.

🎤 One-Line Answer for Interview

"None are truly real-time — choose based on data volume and chaining needs, not assumed immediacy."

Q
Question 092 · Async Apex
What's the difference between synchronous and asynchronous Apex governor limits?
✅ ANSWER

Asynchronous Apex contexts generally get higher limits than synchronous contexts — with the genuine advantage that Batch Apex's chunking resets limits per execute() call, effectively enabling unlimited total rows processed across the full job.

🌍 Real World Example (XYZ Company)

XYZ Company moved a SOQL-heavy reporting process from a synchronous Visualforce controller into a Queueable job specifically to take advantage of async Apex's more generous limit allowances.

🎤 One-Line Answer for Interview

"Async contexts provide more generous governor limits, especially when combined with Batch's per-chunk resets."

Q
Question 093 · Async Apex
Can you mix multiple async types in a single transaction?
✅ ANSWER

Yes, with constraints — you can enqueue a Queueable job and call a Future method in the same transaction, but a Future method cannot itself call another Future method, and async methods generally cannot be called from within an already-asynchronous context.

🌍 Real World Example (XYZ Company)

XYZ Company's Account trigger both calls a Future method for a quick callout AND enqueues a separate Queueable job for complex follow-up processing, both within the same trigger transaction — valid since neither is calling the other from an async context.

🎤 One-Line Answer for Interview

"Yes — the key constraint is never calling one async type from already inside another async execution context."

Q
Question 094 · Async Apex
Why might a callout fail if not run asynchronously?
✅ ANSWER

Salesforce does not allow callouts after a DML operation within the same synchronous transaction. Running the callout asynchronously separates it into its own transaction, avoiding this restriction entirely.

🌍 Real World Example (XYZ Company)

XYZ Company's Account trigger needed to insert a record AND make a callout — attempting both synchronously threw a DML-then-callout exception, which a Future method wrapping just the callout resolved cleanly.

🎤 One-Line Answer for Interview

"Synchronous transactions block callouts after a DML operation — async execution sidesteps this restriction."

Q
Question 095 · Async Apex
What's the practical SOQL limit difference between a single transaction and Batch Apex?
✅ ANSWER

Both share the same 50,000-row SOQL limit per transaction — but Batch Apex's chunking means this 50,000-row limit resets with every execute() call, allowing effectively unlimited total rows processed across the full job.

🌍 Real World Example (XYZ Company)

XYZ Company's batch job never approaches the 50,000-row limit within any single execute() call, even though the job processes millions of Accounts in total across all its chunks combined.

🎤 One-Line Answer for Interview

"The 50,000-row limit is the same per-transaction in both, but Batch Apex's per-chunk reset means the effective total across a full job is far higher."

Q
Question 096 · Async Apex
How does Platform Events relate to the four async Apex tools?
✅ ANSWER

Platform Events are a separate, publish-subscribe-based async mechanism for event-driven architecture — genuinely distinct from Future/Queueable/Batch/Scheduled, which are all about deferring or scaling Apex code execution rather than broadcasting events.

🌍 Real World Example (XYZ Company)

XYZ Company uses Platform Events to notify multiple downstream systems whenever a high-value Opportunity closes, while using Batch Apex separately for the unrelated nightly data cleanup.

🎤 One-Line Answer for Interview

"Platform Events handle event-driven notifications; the four async tools handle deferred or scaled code execution — related concepts, different purposes."

Q
Question 097 · Async Apex
What is a Transaction Finalizer and which async type supports it?
✅ ANSWER

A Finalizer is a guaranteed callback that runs after a Queueable job completes, success or failure — exclusively a Queueable Apex feature.

🌍 Real World Example (XYZ Company)

XYZ Company migrated a critical billing-sync job from Future to Queueable purely to gain Finalizer support, ensuring failures always trigger a guaranteed alert notification.

🎤 One-Line Answer for Interview

"Finalizers are a Queueable-exclusive feature — Future, Batch, and Scheduled Apex have no equivalent guaranteed post-execution callback."

Q
Question 098 · Async Apex
How do Scheduled Flows and Reports compare to true Scheduled Apex?
✅ ANSWER

Scheduled Flows and Scheduled Reports offer simpler, declarative no-code recurring automation for straightforward needs. True Scheduled Apex is reserved for genuinely complex logic declarative tools can't express, or for triggering Batch Apex on a recurring basis.

🌍 Real World Example (XYZ Company)

XYZ Company uses a Scheduled Flow for simple weekly reminder emails, but reserves actual Scheduled Apex for triggering their complex nightly Batch cleanup job.

🎤 One-Line Answer for Interview

"Use declarative scheduled tools when sufficient; reserve true Scheduled Apex for complex logic or triggering Batch jobs."

Q
Question 099 · Async Apex
What's a decision framework for choosing the right async tool?
✅ ANSWER

(1) Simple callout from trigger, no chaining? → Future. (2) Chaining, complex params, or job monitoring at moderate scale? → Queueable. (3) Data volume large enough to need chunk-based limit resets? → Batch Apex. (4) Recurring, scheduled execution? → Scheduled Apex (often combined with Batch).

🌍 Real World Example (XYZ Company)

A strong XYZ Company interview candidate walked through this exact decision tree, naming the specific governor-limit reasoning behind each choice rather than just naming the four tools.

🎤 One-Line Answer for Interview

"Walk through volume, chaining needs, parameter complexity, and recurrence requirements — that's the decision framework interviewers want to hear."

Q
Question 100 · Async Apex
What's the single most common async Apex mistake interviewers ask about?
✅ ANSWER

Querying or performing DML inside a loop, even within properly bulkified async code — the bulkification discipline from trigger handling applies just as strictly inside async Apex, and many candidates incorrectly assume async automatically solves bulkification for them.

🌍 Real World Example (XYZ Company)

A candidate at XYZ Company's interview correctly caught that even inside Batch Apex's execute() method, querying related records inside a per-record loop is still a genuine anti-pattern.

🎤 One-Line Answer for Interview

"SOQL or DML inside a loop — even within async Apex's own execute methods — remains the single most common, most heavily-tested mistake."

Final Takeaway

All four async Apex tools solve the same root problem — staying within governor limits while doing real work — but each does it differently. Future is simplest but most limited. Queueable adds chaining and monitoring. Batch Apex scales to millions of records via chunking. Scheduled Apex adds the recurring trigger. Know the genuine tradeoffs, not just the syntax, and you'll handle any async Apex question confidently.

SF
By SF Interview Pro
Salesforce Interview Prep Team
Practical Q&A by working Salesforce professionals · LWC, Apex, Data Cloud & AI
About Us ↗
☕ Enjoyed this article?
SF Interview Pro is 100% free and maintained by a Salesforce professional. No ads, no paywalls, and no signup required. If this guide helped you prepare for an interview, earn a certification, or grow your Salesforce career, consider buying me a coffee! ☕💜
🇮🇳 UPI (India)
UPI QR Code to support sfinterviewpro
Pay by QR
GPay · PhonePe · Paytm · BHIM
🌎 International
PayPal QR Code to support sfinterviewpro Pay via PayPal ↗
Scan or tap to pay