I'm refactoring a Visualforce page, which currently gets data from a synchronous Apex callout, so that the callout will asynchronous. The Visualforce page downloads a .csv file with customer data in it. In some instances the customer data exceeds the 6MB limit for synchronous Apex callouts. Asynchronous calls have a 12MB limit, so the technical direction given is to utilize that with Continuation
.
But I'm running into an issue where the Visualforce page is not returning the data after having made the switch to use an asynchronous call. I'm following the steps Salesforce has documented for making long-running callouts with Continuation
. Here's a breakdown:
I have a CommonController
class that calls an endpoint. That class is called by a APIUtils
class, which gets called by a HistoryController
class; HistoryController
is called by the Visualforce page.
CommonController.cls:
The CommonController
class makes an HttpRequest
to an endpoint using Continuation
.
public static string methodStr;
@AuraEnabled(continuation=true)
public static Object invokeAPIContinuation(String servicePath, String httpMethod,
String httpBody,Map<String,String> metaDataMap){
String serviceEndPoint;
Continuation con = new Continuation(40);
con.ContinuationMethod = 'conResponseHandler';
// the rest of this method is unchanged from the synchronous way...
serviceEndPoint = metaDataMap.get('APIEndpoint');
String apiEndPoint= serviceEndPoint + servicePath;
HttpRequest httpRequest = new HttpRequest();
httpRequest.setMethod(httpMethod);
httpRequest.setHeader('Content-Type', 'application/json');
String crtNo = metaDataMap.get('APICertName');
httpRequest.setClientCertificateName(crtNo);
httpRequest.setEndpoint(apiEndPoint);
if(httpMethod.endsWithIgnoreCase('POST')) {
httpRequest.setBody(httpBody);
methodStr = 'POST';
}
Integer timeOut = Integer.valueof(metaDataMap.get('TimeOut'));
httpRequest.setTimeout(timeOut);
con.addHttpRequest(httpRequest);
return con;
}
// make a callback method as outlined in the Salesforce documentation for Continuation...
public static String conResponseHandler(List<String> labels, Object state){
// Get the response by using the unique label
HttpResponse httpResponse = Continuation.getResponse(labels[0]);
// Set the result variable
String responseBody = httpResponse.getBody();
String response = '';
if(httpResponse.getStatusCode() == 200 ) {
responseBody = httpResponse.getBody();
if(methodStr == 'POST') {
responseBody = 'success';
}
}
return responseBody;
}
APIUtils.cls
The APIUtils
class calls invokeAPIContinuation
from the CommonController
class.
public static void getEmployeeDetailsDataCont(String billingNumber, String enterpriseId, String billingControlNumber, Map<String,String> metaDataMap,String benefitType) {
String servicePath = billingNumber +'/Members?EmployerId=' + enterpriseId + '&BenefitType=' + benefitType;
CommonController.invokeAPIContinuation(servicePath, 'GET', '',metaDataMap);
}
HistoryController.cls:
The HistoryController
class calls getEmployeeDetailsDataCont
from the APIUtils
class.
public void exportEmployeeDataToCsvFile() {
String empTypeParam = ApexPages.currentPage().getParameters().get('empType');
if(empTypeParam.equalsIgnoreCase('GB')) {
contentType = 'text/vnd.ms-excel#groupDetails.csv';
}else {
contentType = 'text/vnd.ms-excel#voluntaryDetails.csv';
}
String billingNumber = ApexPages.currentPage().getParameters().get('billingNumber');
Map<String,String> metaDataMap = CommonController.getmetaDataValues();// = getBillingMetaDataForVFPage();
// comment out previous method to use the new Continuation method
// csvFileEmployeeData = APIUtils.getEmployeeDetailsData(billingNumber,CommonController.getEmployerIdFromLoggedInUser(),'',metaDataMap,empTypeParam);
APIUtils.getEmployeeDetailsDataCont(billingNumber,CommonController.getEmployerIdFromLoggedInUser(),'',metaDataMap,empTypeParam);
}
Visualforce page:
<apex:page controller="HistoryController" contentType="{!contentType}" action="{!exportEmployeeDataToCsvFile}">{!csvFileEmployeeData}</apex:page>
But my Visualforce page is not returning data after the asynchronous call. I suspect this may have partially to do with the APIUtils
class method previously returned a string but now returns a void. At this point I'm pretty stumped.
HTTP callout processing time is not included when calculating this limit. We pause the timer for the callout and resume it when the callout completes