Skip to main content

SF-0405 · Scenario · Hard

Among Batch apex, Future method and Queueable apex, which one can cause issues if we schedule them?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

None of the three (Batch, Future, Queueable) can be passed directly to System.schedule — only Schedulable classes can. But each behaves differently when invoked from a Schedulable’s execute. The one that causes the most issues under heavy schedules is Batch Apex.

Quick comparison

Async typeSchedulable directly?Invoke from Schedulable.execute?Common issues when scheduled
FutureNoAllowedCannot be uniquely “scheduled” — each invocation is one-shot. Fewer issues, but limited capability.
QueueableNoAllowedGenerally well-behaved. Watch the 50-per-transaction enqueue limit.
Batch ApexYes (if dual-implements Schedulable)Allowed via Database.executeBatchApex Flex Queue can fill up; 100-Holding cap is the most common failure.

Why Batch causes the most scheduling issues

1. Flex Queue cap

Batch jobs use the Apex Flex Queue: 5 Processing + 100 Holding = 105 max. If your scheduled batch runs faster than it completes — say, scheduled every 10 minutes but takes 15 minutes to run — jobs pile up. After a few hours, the queue fills:

System.LimitException: Attempt to add a job to the apex flex queue failed because the queue is full.

2. Overlapping runs

public class OverlappingBatch implements Schedulable {
    public void execute(SchedulableContext ctx) {
        Database.executeBatch(new HeavyBatch(), 200);
    }
}

System.schedule('Every 5 minutes', '0 */5 * * * ?', new OverlappingBatch());

If HeavyBatch takes 7 minutes, run #2 starts before run #1 finishes — both compete for the same queue slot. After a few hours, dozens of batches are Holding, none completing.

3. Long-running batch blocks deploys

You can’t deploy changes to a class that’s actively scheduled or running. A long-running scheduled batch can keep a developer blocked.

Why Future scheduling is “limited”

@future cannot be scheduled directly because it’s not a class — it’s a method annotation. You can only invoke a future method from inside a Schedulable’s execute:

public class FutureCaller implements Schedulable {
    public void execute(SchedulableContext ctx) {
        MyService.doStuffAsync(getIds());
    }
}

public class MyService {
    @future
    public static void doStuffAsync(List<Id> ids) { /* ... */ }
}

Issues with this pattern:

  • Only 50 future calls per transaction — fine for one call from a Schedulable, but tighter than other options.
  • Future cannot make sObject parameters — only primitives.
  • No JobId, no chaining — once enqueued, you can’t track its position or compose multiple steps.

For new code, prefer Queueable over future every time.

Why Queueable is the safest

Queueable from a Schedulable is the modern recommended pattern:

public class QueueableCaller implements Schedulable {
    public void execute(SchedulableContext ctx) {
        System.enqueueJob(new MyQueueable());
    }
}
  • No Flex Queue contention (Queueable uses a separate, much larger queue).
  • Returns a JobId for tracking.
  • Can chain.
  • Accepts sObjects and complex types.
  • Callouts via Database.AllowsCallouts.

The only Queueable failure mode under schedules is daily async limit exhaustion (250,000 jobs/24 hours), and that affects all three types equally.

What an interviewer is testing

The question is really “do you know that:

  1. Only Schedulable can be passed to System.schedule?
  2. Batch Apex needs a wrapper and contends with the Flex Queue?
  3. Future is awkward to schedule and outdated?
  4. Queueable is the cleanest async to invoke from a schedule?”

Common interview follow-ups

  • Why can’t you schedule a future method? — Future is a method annotation, not a class. System.schedule requires a class instance.
  • What’s the workaround for scheduling a future? — Wrap in a Schedulable; call the future from execute.
  • Which is best practice in 2026? — Schedulable invoking Queueable. Use Batch only when you need 50K+ records processed asynchronously.

Verified against: Apex Developer Guide — Asynchronous Apex Limits. Last reviewed 2026-05-17.