I have a batch job that needs to callout to an external web service and retrieve a variable number of records. Seems like a perfect use-case to have an iterator which performs the callouts until there are no more results.
However, if the webservice returns many records (in separate paginated callouts) the batch job will hit the maximum callout timeout limit while it is being prepared. This leads me to conclude that the start method is querying for all results instead of lazy-loading them 100,200 at a time when it hits the execute method.
Is there any way to do these callouts in the iterator or do I just need to move them inside the execute method?
This is my current code
global with sharing class myBatch implements Database.Batchable<wrapperClass>, Database.AllowsCallouts, Database.Stateful{
global Iterable<wrapperClass> start(Database.BatchableContext BC) {
return new myIterator();
}
global void execute(Database.BatchableContext BC, List<wrapperClass> scope) {
//do some stuff. never gets here.
}
}
global with sharing class myIterator implements Iterator<wrapperClass>, iterable<wrapperClass> {
public List<wrapperClass> myData;
private Integer index = 0;
private Boolean APIHasMore = true;
global myIterator() {
//do initial callout for records, 100 at a time
//deserialize json into myData
}
global boolean hasNext() {
return index<myData.size()-1 || APIHasMore;
}
global wrapperClass next() {
if(index<myData.size()-1){
index++;
return myData[index-1];
}
else{
//callout for next 100 records and deserialize into myData, if there are no more set APIHasMore to false
index = 0;
index++;
return myData[index-1];
}
}
global Iterator<wrapperClass> Iterator() {
return this;
}
}
Exception: First error: Exceeded maximum time allotted for callout (120000 ms)