I am making a callout to a webservice to retrieve records and upsert them into Salesforce. When I execute my batch class with a small set of records, they're inserted in Salesforce properly.
However when I expand the scope of records I hit the 'too many callouts 101' error. In looking at the debug log, the line where I'm facing the issue is cod = getOutBoundRecords(str)
I see that because it's inside a for loop it's triggering this error. Because the web service doesn't have a method to retrieve records in bulk, I have to make a callout for each individual
record. Is there a way to make multiple callouts without hitting this error? Thank you.
Class
public class ConcordBuilder implements Database.AllowsCallouts {
//Build Fax records and get Get details (Callout)
public static void getListOutBoundRecords(DateTime endDate ){
map<string,Custom__c> COD2Update = new map <string,Custom__c>(); // index of records by job id
Concord__c con = new Concord__c();
List<Custom__c> stConcord = new List<Custom__c>();
accountmanagementreportingwebservice2.AccountManagementReportingWebserviceSoap s= new accountmanagementreportingwebservice2.AccountManagementReportingWebserviceSoap();
accountmanagementreportingwebservice2.ListOutboundActivityRequest req = new accountmanagementreportingwebservice2.ListOutboundActivityRequest();
accountmanagementreportingwebservice2.ListOutboundActivityResponse res = new accountmanagementreportingwebservice2.ListOutboundActivityResponse();
accountmanagementreportingwebservice2.Authentication a =new accountmanagementreportingwebservice2.Authentication();
//Auth for ListOutbound Class
a.Username = '-------';
a.Password = '-------!';
req.Authentication = a;
req.CustomerId = 1224;
req.ExcludeSubLevelEntries = Boolean.valueOf('true');
req.PageIndex = 0;
req.PageSize = 100;
req.SortOption = 0;
s.timeout_x = 120000;
req.StartDate = datetime.valueOf('2019-11-1' + '' + ' 06:05:05');
req.EndDate = datetime.now();
// Make the callout to get Job Ids
res = s.ListOutboundActivity(req);
String jsonResponse = (JSON.serializePretty(res));
JSON2APex result = JSON2APex.parse(jsonResponse);
set<string> jobIds = new set<string>();
//****************** Parse the first callout response and build records
Custom__c co = new Custom__c();
system.debug('Total Records = ' +result.TotalRecords);
if(result.TotalRecords >0){
for(JSON2APex.Om om: result.OutboundMessageList.om){
system.debug(om);
co.Duration__c = om.dur;
co.Delivery_Attempts__c = om.atmpts;
co.Delivered_Pages__c = om.pgct;
co.JOB_ID__c = om.id;
co.Concord_Account_ID__c = String.valueOf(om.cid);
co.Sender_Country__c = om.fcc;
co.Recipient_Fax_Number__c = om.fax;
co.Status__c = om.stat_x;
system.debug(co);
//index of Concord Records
COD2Update.put(co.JOB_ID__c, co);
}
}
Custom__c cod = new Custom__c(); //stores fax details
Custom__c cod2 = new Custom__c(); // to be updated
system.debug(COD2Update.keyset());
//loop over Job IDs and
for(string str :COD2Update.keyset()){
System.debug('First JobId is :' + str);
//****************Line below is causing callout error
cod = getOutBoundRecords(str);
System.debug('Call Out response');
System.debug(cod);
cod2 = COD2Update.get(str);
System.debug('Soon to be updated');
System.debug(cod2);
// cod2 = COD2Update.get(str);
if(cod2 != null){
cod2.Start_Date__c = cod.Start_Date__c;
cod2.Stop_Date__c = cod.Stop_Date__c;
cod2.Submitted_Date__c = cod.Submitted_Date__c;
cod2.Scheduled_Date__c = cod.Scheduled_Date__c;
cod2.Status_Description__c = cod.Status_Description__c;
cod2.Speed__c = cod.Speed__c;
cod2.Name = cod.Name;
cod2.Recipient_Country__c = cod.Recipient_Country__c;
cod2.Recipient_Name__c = cod.Recipient_Name__c;
cod2.Recipient_City__c = cod.Recipient_City__c;
cod2.JOB_ID__c = str;
cod2.Duration__c = cod.Duration__c;
cod2.Page_Count__c = cod.Page_Count__c;
cod2.Sender_Fax_Number__c = cod.Sender_Fax_Number__c ;
cod2.Sender_CSID__c = cod.Sender_CSID__c;
cod2.Sender_Name__c = cod.Sender_Name__c ;
cod2.Sender_City__c = cod.Sender_City__c;
//overwrite existings with updated
COD2Update.put(cod2.JOB_ID__c,cod2);
}
}
upsert COD2Update.values();
system.debug(JSON.serializePretty(COD2Update));
}// end method
//Get Fax Details
public static Concord__c getOutBoundRecords(string Jobid){
// public static void getOutBoundRecords(string Jobid){
Custom__c conc = new Custom__c ();
accountmanagementreportingwebservice2.AccountManagementReportingWebserviceSoap s= new accountmanagementreportingwebservice2.AccountManagementReportingWebserviceSoap();
accountmanagementreportingwebservice2.GetOutboundDetailRequest req = new accountmanagementreportingwebservice2.GetOutboundDetailRequest();
accountmanagementreportingwebservice2.GetOutboundDetailResponse res = new accountmanagementreportingwebservice2.GetOutboundDetailResponse();
accountmanagementreportingwebservice2.Authentication a = new accountmanagementreportingwebservice2.Authentication();
a.Username = '----------';
a.Password = '--------';
req.Authentication = a;
req.JobId = Jobid;
res = s.GetOutboundDetail(req);
String jsonResponse = (JSON.serializePretty(res));
//Retrieve the JSON response from the second callout and map the Custom__c fields with SF fields
String jsonResponse2 = (JSON.serializePretty(res));
JSON2ApexOFD results = JSON2ApexOFD.parse(jsonResponse2);
for(JSON2ApexOFD.OutboundFaxDetail om2: results.OutboundFaxMessage.OutboundFaxDetail){
String convertTime = om2.StartDt;
String Startruncated = convertTime.left(convertTime.length()-5);
String truncated2 = Startruncated.replace('T',' ');
conc.Start_Date__c = DateTime.valueOf(truncated2);
String convertTimestop = om2.StopDt;
String Stoptruncated = convertTimestop.left(convertTime.length()-5);
String truncated3 = Stoptruncated.replace('T',' ');
conc.Stop_Date__c = DateTime.valueOf(truncated3);
conc.Duration__c = om2.Duration;
String convertTimeSubmit = om2.SubmitDt;
String Submittruncated = convertTimeSubmit.left(convertTime.length()-5);
String truncated4 = Submittruncated.replace('T',' ');
conc.Submitted_Date__c = DateTime.valueOf(truncated4);
String convertSchedule = om2.ScheduledDt;
String Scheduletruncated = convertTimeSubmit.left(convertTime.length()-5);
String truncated5 = Scheduletruncated.replace('T',' ');
conc.Scheduled_Date__c = DateTime.valueOf(truncated5);
conc.Name = om2.SenderDeptName;
conc.Recipient_Country__c = om2.RecipientCountry;
conc.Recipient_City__c = om2.RecipientCity;
conc.Recipient_Name__c = om2.RecipientName;
conc.Speed__c = om2.Speed;
if(om2.PageCount != null){ conc.Page_Count__c = om2.PageCount;}
if(om2.SenderFax != null){conc.Sender_Fax_Number__c = om2.SenderFax;}
conc.Sender_Name__c = om2.SenderName;
conc.Sender_CSID__c = om2.SenderCSID;
conc.Sender_Country__c = om2.SenderCountry;
conc.Sender_City__c = om2.SenderCity;
}
if (conc != null){
return conc;
} else{
system.debug('no record found for '+ Jobid );
return null;
}
}
}// end class
Batch Class
global class BatchableClass implements Database.Batchable<SObject>, Database.AllowsCallouts {
global BatchableClass (){
}
global Database.QueryLocator start(Database.BatchableContext BC){
String soql = 'Select Id, JOB_ID__c from Custom__c LImit 1';
return database.getQueryLocator(soql);
}
global void execute(Database.BatchableContext BC, List<Custom__c> scope){
Datetime endDate = System.today();
Builder.getListOutBoundRecords( endDate);
}
global void finish(Database.BatchableContext BC){
System.debug('Success');
}
}
COD2Update
populated? Fundamentally you need to chunk this work into smaller pieces that can run in a single invocation ofexecute()
. – David Reed♦ Nov 27 '19 at 21:34