3

I read the documentation here regarding batch execution.I have batch class that call Http call out from another class.All together need to execute 6 HttpCallout per record.I cannot separate the HttpCallOut into different batch because the result from call out is related and need to be in sequence.

I set in Scheduler class MyBatch c = new MyBatch (); Database.executeBatch(c,1);

The record that currently need to be processed are 157 records.Now it hitting System.LimitException: Too many callouts: 11 which I don't understand because I already set the scope = 1. What should I do?If I set limit of record in Database.getQueryLocator ,for example only 10 record perquery , how can I make sure the rest of other record can be processed ? Or another way that I am thinking is to execute another batch job once it hit the limit but I am not sure if this possible?

I am not sure how to paste the code here because my code is quite complex and it give me warning that my question will contain a lot of code.

Thanks in advance.

Edited:to show where I did the mistake.Notice I call the callout inside mapMyObject loop where mapMyObject value keep increasing.

Example this is the class that contain callout methods.

global class MyCallOut {
     public static string getUserByEmail(string email){
                 //HttpRequest bla bla
     }

    public static string populateProfile(string str{

             //HttpRequest bla bla
    }

   //more httpcall method    
}

MyBatch class, the caller:

 global  class MyBatch implements   Database.Batchable<sObject>, Schedulable, Database.Stateful,Database.AllowsCallouts {      

String query='Select Id,Name,Status__c,UserId from Transaction__c where Status__c='\'Pending\'';
Map<String, MyObject> mapMyObject  = new Map<String, MyObject>();

public MyBatch(){
         //contructor contain initialization
       }

        global void execute(SchedulableContext sc) {}

            global Database.QueryLocator start(Database.BatchableContext BC){

            return Database.getQueryLocator(query);
           }

        global void execute(Database.BatchableContext BC, List<Transaction__c> transactions) {
                  for(Transaction__c t:transactions){
                       mapMyObject.put(t.UserId,new MyObject(Name='Bla bla');
                  }

                  system.debug('mapMyObject size '+mapMyObject.size());

                 for (MyObject o : mapMyObject.Values()){
                   //contain logic and call out
                   MyCallOut.getUserByEmail(email)
                  //the rest of logic and call cout
                 }
             }
    }
5
  • Checkout the edited question, do you mean I MyBatch class should call another Batch class?Can we keep the sequence of the httpcallout with that?I am more than glad if you can provide example.
    – unidha
    Commented Feb 7, 2014 at 11:28
  • 2
    You have the right general approach: if you need 6 callouts per batch, running in batches of 1 should prevent the problem. I suggest you start by adding some simple debug.log() statements before each callout, and inspecting the log from a failed run. It sounds as if you are somehow running additional callouts per batch. Do you have any triggers that make callouts, that could be getting invoked? Commented Feb 7, 2014 at 12:35
  • 1
    Agreed, it looks fine in principle. Get a full debug log of one execute() run and see why it's doing more than 6 callouts. Better yet, just copy/paste and run the contents of the execute() in an Execute Anonymous window and watch the log. Commented Feb 7, 2014 at 19:01
  • Thanks for the hint.Yes, even I set the batch scope to one but I calling the callout inside the mapMyObject will keep increasing.
    – unidha
    Commented Feb 10, 2014 at 6:13
  • Thanks @JasonClark and @JeremyNottingham for the hint ,the correct way is to reset map in transaction loop like this for(Transaction__c t:transactions){ **mapMyObject =new Map<String,MyObject>();** mapMyObject.put(t.UserId,new MyObject(Name='Bla bla'); }
    – unidha
    Commented Feb 10, 2014 at 6:23

1 Answer 1

1

Thanks to @JasonClark and @JeremyNottingham for the hint.Now I am able to understand the concept correctly.When we set scope equal to one,it will process our record one by one.In my case , it will process transaction list one by one and one record qualified for 10 call out.

The mistake that I did is I add value into map inside transaction loop WITHOUT instantiate it.So everytime the batch job run , it will process each of transaction but will keep adding new value into map.

So the call out is execute is done inside map loop.First job it will pass because the map value is one, but second job will fail because the map value already two.If the callout is 6 per record, it will be 12 and hit the limit.

This is how I fix it

for(Transaction__c t:transactions){ 
        mapMyObject =new Map<String,MyObject>();
        mapMyObject.put(t.UserId,new MyObject(Name='Bla bla');
    }

Again, thanks for your response.Really appreciate it :)

1
  • unidha, you can mark this question as resolved by clicking the (V) button on the left of your own answer. Commented Apr 11, 2014 at 8:07

You must log in to answer this question.

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