I am able to do callout using apex batch with user interaction (on demand). So when user click the button, this apex batch will run without any problem
calling the apex batch:
global class InvoiceHeaderListController {
public static HttpCalloutMock mock{get;set;}
public ResponseData rData{get;set;}
public String lastNum{get;set;}
public Boolean hasNext{get;set;}
private static final String ENDPOINT_HEADER = Label.BP_Invoice_Header;
private static final String API_KEY = Label.BP_Api_Key;
public void doSearch() {
lastNum = '0';
hasNext = false;
getInvoiceHeader(lastNum);
List<InvoiceData> invoiceDataList = getInvoiceHeaderRows(rData);
do {
getInvoiceHeader(lastNum);
List<InvoiceData> anotherList = getInvoiceHeaderRows(rData);
invoiceDataList.addAll(anotherList);
}
while(hasNext == true);
//call the apex batch
InvoiceHeaderBatch ihb = new InvoiceHeaderBatch(invoiceDataList);
Database.executeBatch(ihb, 100);
}
public HttpResponse getInvoiceHeader(String lastRowNum) {
Http httpObj = new Http();
HttpRequest requestObj = new HttpRequest();
HttpResponse responseObj = null;
String reqEndpoint = ENDPOINT_HEADER + '?';
reqEndpoint = reqEndpoint + 'apiKey=' + API_KEY;
reqEndpoint = reqEndpoint + '&' + 'lastRowNum=' + (String.isNotBlank(lastRowNum) ? lastRowNum : '0');
requestObj.setEndpoint(reqEndpoint);
requestObj.setMethod('GET');
requestObj.setHeader('Content-Type', 'application/json');
if (Test.isRunningTest() && mock != null) {
responseObj = mock.respond(requestObj);
}
else {
responseObj = httpObj.send(requestObj);
}
if (responseObj.getStatusCode() != 200) {
System.debug(LoggingLevel.DEBUG, '***The status code returned was not expected: ' + responseObj.getStatusCode() + ' ' + responseObj.getStatus());
}
else {
String responseString = responseObj.getBody();
rData = (InvoiceHeaderListController.ResponseData) JSON.deserialize(responseString, InvoiceHeaderListController.ResponseData.class);
}
return responseObj;
}
public List<InvoiceData> getInvoiceHeaderRows(ResponseData rd) {
List<InvoiceData> resultList = rd.receivableInvoices;
}
public class ResponseData {
public List<InvoiceData> receivableInvoices{get;set;}
public String lastRowNum{get;set;}
public Boolean hasNext{get;set;}
}
public class InvoiceData {
String invoicenumber{get;set;}
String invoicestatus{get;set;}
}
}
apex batch class:
global class InvoiceHeaderBatch implements Database.Batchable<InvoiceHeaderListController.InvoiceData>, Database.Stateful, Database.AllowsCallouts {
global List<InvoiceHeaderListController.InvoiceData> invoiceDataList = new List<InvoiceHeaderListController.InvoiceData>();
global Map<String, Invoice__c> invoiceMapToUpsert = new Map<String, Invoice__c>();
global Integer recordsProcessed = 0;
global InvoiceHeaderBatch(List<InvoiceHeaderListController.InvoiceData> invDataList) {
this.invoiceDataList = invDataList;
}
global System.Iterable<InvoiceHeaderListController.InvoiceData> start(Database.BatchableContext bc) {
return this.invoiceDataList;
}
global void execute(Database.BatchableContext bc, List<InvoiceHeaderListController.InvoiceData> scope) {
for (InvoiceHeaderListController.InvoiceData iData : scope) {
//do stuff
recordsProcessed = recordsProcessed + 1;
}
}
global void finish(Database.BatchableContext bc) {
System.debug(LoggingLevel.DEBUG, '***TOTAL: ' + recordsProcessed);
}
}
I tried to schedule the apex batch to do the callout apex batch daily:
global class InvoiceHeaderListSchedule implements Schedulable {
global void execute(SchedulableContext sc) {
InvoiceHeaderListController.doSearch();
}
}
When the apex batch run, I got the following error:
System.CalloutException: Callout from scheduled Apex not supported.
Is there any workaround to run apex batch callout with schedule?
EDIT
I am updating the callout to run in future:
@future(callout=true)
public static void doSearch() {
...
}
and got error:
System.AsyncException: Database.executeBatch cannot be called from a batch start, batch execute, or future method.
I ran out of ideas about how to schedule callout apex batch. Is this impossible thing to do?