Can Queueable solve "Future method cannot be called from a future or batch method"?

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).


Wasted about 2 months to get an answer from salesforce support why I get

Too many queueable jobs added to the queue: 2

when documentation (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_queueing_jobs.htm) says that the limit is 50 for entry point?

The root cause was in the undocumented limit for invocation of System.enqueueJob from batch context mentioned by @sfdcfox

In my case, to prevent hitting of this limit I checked the context in which my method executes, see code below:

if (FALSE == System.isBatch() || FALSE == System.isFuture()) {
    System.enqueueJob(worker);
}

You can prevent this by checking the limit before enqueuing:

if(Limits.getQueueableJobs() < Limits.getLimitQueueableJobs()){
   System.enqueueJob(worker);
}