[SalesForce] Can Queueable solve “Future method cannot be called from a future or batch method”

I have code that must be called as @future as it requires all the resources one can get. The only problem is that in 1% of the cases this code is called from a Batch and therefore fails with

System.AsyncException: Future method cannot be called from a future or
batch method

Is the new Queueable interface a solution to this? Meaning can I convert this @future into an Apex class that implements Queueable and fix this problem?

Or would I need to convert my calling Batch into a series of Queueable calls?

What I already tried:

I tried to call multiple Queueable's (one per record) from the Batch and ran into

Too many queueable jobs added to the queue: 2

When I instead passed in a List<Id> and let the Queueable to iterate through this list be restarting itsself for remaining records in its execute() method I got

Maximum stack depth has been reached.

Best Answer

Yes, Queueable can be called from Database.Batchable classes. You must go through enqueueJob for this to work:

public class BatchClass implements Database.Batchable<SObject> {
    public Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator([SELECT Id FROM Account]);
    }
    public void execute(Database.BatchableContext context, Account[] records) {
        System.enqueueJob(new QueueClass(new Map<Id, Account>(records).keySet()));
    }
    public void finish(Database.BatchableContext context) {
    }
}

public class QueueClass implements Queueable {
    Set<Id> recordids;
    public QueueClass(Set<Id> recordIds) {
        this.recordIds = recordIds;
    }
    public void execute(QueueableContext context) {
         // Do something here
    }
}

Note that you're limited to just one enqueueJob call per execute in the Database.Batchable class. This is to prevent explosive execution (a so-called "Rabbit Virus" effect).