6

I got a situation where i need to invoke future method from batch class. And i know that it is not possible to do. But there might be some workarounds to achieve it, right? And i dont want to invoke future method using shedule apex as my requirement will hit governor limits of "Total number of schedule jobs exceed". So i tried in below ways, but still fighting with same issue.

My design is

Scenario 1 :

  1. Schedule Apex ===> 2. BatchClass (Runs every hour) (Generates a map with "N" records for every batch context, and passes it to Future method in an apex class) ===> 3. Future method ( then it will login to a salesforce account and generates an attachment and sends an email to a corresponding email address) .

Scenario 2 :

Since, It is not possible to invoke future method from batch, i tried implementing an apex class with a normal static method invoking future method and in a batch class, for every context i.e., execute() method, it will invoke a normal method which in turn invokes future method, but still got the same error

FATAL ERROR: Future method cant be called from future or Batch

ie.,

global class BatchClass implements Database.batachable<Sobject> {

  global Iterable<ScheduledReport__c> start(Database.BatchableContext BC)  {

       query=[];
       return query;
 }

global void execute(Database.BatchableContext BC, List<ScheduledReport__c> scope) {
     FutureClass.normalMethod(mapRecords);
  }

  global void finish(Database.BatchableContext BC){
  }

}

Future Class:

global class FutureClass {

global static void normalMethod(Map<> mapR) {

    futureMethod(mapR);

}

@future(callout=true)

global static void futureMethod(Map<> m) {

    //some code;

 }

}

Scenario 3 :

Instead of invoking future class method from batch i tried updating list of records and done checkbox value to true and i've implemented after update event trigger to get the all the records in which checkbox values are true and from trigger i tried invoking future method , still didnt work , i got an error

FATAL ERROR: Future method cant be called from future or Batch

Please help me out.

Thanks !

1
  • 3
    Been answered, OP MIA, keeps coming up as a community bump
    – Eric
    Oct 13, 2015 at 13:06

2 Answers 2

4

Definitely you can use an HTTP callout as an escape mechanism. But this is pretty naughty. You'll need a Remote Site Setting and a Session ID and a global class etc etc etc (red flags, alarm bells).

May I humbly recommend the use of System.Queueable call instead of @Future. You can create a class that is constructed with any kind of argument that you want to hand in, like so:

public class DeferredHandler implements System.Queueable
{

    private Map<String,String> key2val;

    public DeferredHandler(Map<String,String> key2val) {
        this.key2val = key2val;
    }

    public void execute(System.QueueableContext objContext)
    {
        //do your @Future stuff here with this.key2val
    }

}

And invoke him from inside your batch like this:

//defer stuff
System.Queueable job = new DeferredHandler(key2val);
System.enqueueJob(job);

There is some literature about this in the docs and Josh Kaplan's awesome Queueable blog post.

8
  • 1
    I really appreciate for your time, In my batch class it will process 10 records per context as we've call out limit. so if there are 1000 records retrieved in start method and then it will form 100 batches ( 10 * 100 = 1000) , right ? So if i invoke Queueable (i.e., DeferredHandler ) class in batch execute() method, then 100 jobs will be added in Queueable Apex, but in the above document the limit is set to 50 jobs per transaction. I am bit confused, 50 jobs per transaction means, can we add 50 queueable jobs for every context while running batch ??? Nov 27, 2014 at 5:10
  • 1
    Wow, it's working great in developer organisation but coming to sandbox i am getting an error saying " Method is not implemented ", it seems my sandbox (cs14) isn't upgraded, right ? Nov 28, 2014 at 6:08
  • Yep. Just open a case. They'll sort ya out. @CollegeManagement Nov 28, 2014 at 19:36
  • @CollegeManagement the HTTP callout limit is 50 these days. Yes, I think you are able to enqueue up to 50 Queueables inside each execute() method. Nov 28, 2014 at 19:43
  • 1
    You are really awesome man, Thank you soo much ! It's working gr8. I've one more issue, As per gov limits i can only able to schedule 5 batches, But i want to schedule 'N' number of batches. Suppose I've 100 users, i want to run 1 batch per user, therefore, totally 100 batches. Is there any workaround to it ? Dec 1, 2014 at 6:46
2

As this Asynchronous Processing in Force.com document illustrates, each execute call of your batchable implementation is being executed in the same sort of asynchronous manner (e.g. in its own new set of governor limits) as an @future call is executing in. And you can make HTTP callouts from the execute method. And by using the batchable mechanism, the execute calls are guaranteed to be run one after another and so only every contribute one long running concurrent operation.

So I suggest that you do not need to make the @future call at all: do the work in the execute method or supporting non-@future methods.

1
  • As you said if i implement rest code setting time limit for 120 sec (i.e, request.setTimeout(120000)) in batch execute() it is working fine as it is processing 100 records, but i am afraid that i will get struck with same error if it process thousands of records. Nov 27, 2014 at 4:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .