[SalesForce] Concurrent Request Limit Exceeded – Possible Solutions

In the recent past we've replaced two very old s-control type and html mashups with visual force pages and web services. This changes along with a few other visual force pages built into our standard Account page has create a scenario where we are hitting the Concurrent Request error a few times a week.

I have taken some time to redesign one of the java web services to implement an asynchronous pattern. I'm trying to get the apex callout to use continuation.

Since this is not processing related but necessary to fully load the UI, I want this continuation to execute on load of the page. Right now, I can get the class to load but in the debugger timeline view, no callout is made.

In articles I've read it appears only possible to have the section of the visual force page reloaded on some action. Do I need to call the Continuation straight from my visualforce page or can the extension call it and bubble the response up?

Visualforce page:

<apex:page standardController="Account" extensions="InformationExtension2">
    <apex:outputPanel id="Info">
    <table id="summary">
        <tr><th colspan="5"><apex:outputText >{!id}</apex:outputText></th></tr>
        <tr class="summaryHeaderRow">
            <th></th>
            <th colspan="3" class="headerRow">Registration</th>
            <th colspan="3" class="headerRow">Accounts</th>
            <th class="headerRow">Value</th>
            <th class="headerRow">As Of</th>
            <th class="headerRow">%</th>
        </tr>

        <!-- Additional Table Information-->

    </apex:outputPanel>
    </apex:page>

Extension:

public InformationExtension2(ApexPages.StandardController controller) {
    this.acct = (Account)controller.getRecord();
    custId = getThisCustId();
    getInformation();
}
public void  getInformation()
{

    System.debug(custId);
    InformationContinuation continuation = new InformationContinuation(custId);
    InformationSubtotal subtotals = new InformationSubtotal();
    Information info = new Information();
    try{
        Object testing = continuation.getInfoCon();
        if(testing==null)
        {
            System.debug(LoggingLevel.FINE,'Continuation returned null');
        }
        else{
            System.debug(LoggingLevel.FINE,'Continuation returned with response');
            System.debug(LoggingLevel.FINE,'Continuation returned '+continuation.pi);
            info=continuation.pi;
        }
    .... Additional Processing
    }
}

Class containing the continuation

public class InformationContinuation {

String custId{get;set;}
String requestLabel;
Object result;
public Information info;set;}

/*Constructor*/
public InformationContinuation(String custId)
{
    this.custId = custId;
}

//Action Method
public Object getInfoCon(){

    //create continuation with timeout
    Continuation con = new Continuation(60);

    //Set the callback method for the resonse
    con.continuationMethod = 'processResponse';

    //Create the callout request
    HttpRequest req = new HttpRequest();
    req.setClientCertificateName('InfoService');
    req.setMethod('GET');
    req.setEndpoint(SERVICE_ENDPOINT+this.custId);

    //Add callout request to continuation
    this.requestLabel = con.addHttpRequest(req);

    return con;
}

public Object processResponse(){
        System.debug(LoggingLevel.FINE,'received response to process');
        //get the response by using the unique label
        HttpResponse response = Continuation.getResponse(this.requestLabel);
        Integer statusCode = response.getStatusCode();

        //Check the status code
        if(statusCode==2000)
        {
            System.debug(LoggingLevel.ERROR,'The request timeout was reached');
            return null;
        }
        if(statusCode==2001)
        {
            System.debug(LoggingLevel.ERROR,'There was a connection failure');
            return null;
        }
        if(statusCode==2002)
        {
            System.debug(LoggingLevel.ERROR,'The request timeout was reached');
            return null;
        }
        if(statusCode==2003)
        {
            System.debug(LoggingLevel.ERROR,'The response hasn\'t arrived. Also means the async '
                        +'framework hasn\'t resumed');
            return null;
        }
        if(statusCode==2004)
        {
            System.debug(LoggingLevel.ERROR,'The response is too large');
            return null;
        }
        if(String.isEmpty(response.getBody())){
           info=null;
           System.debug(LoggingLevel.ERROR,'Response from webservice is empty, blank or null');
         }else
          { //Process the JSON response }...
    }
}

Best Answer

I found a solution to completing this request on page load but only if the continuation was built in the extension and not called from the extension. I still propose that it's possible, but due to deadlines and trying to get other work done, have buckled and gone on to the most common solution found online.

A tip for any of you using Certificates, if the certificate is bad, and your running this live, you won't receive a certificate error in the log. You should try running the callout in the execute anonymous window and it if it is a certificate issue, you'll see pop-up indicating a fatal error has occured due to the bad certificate.

If anyone needs the entire solution posted, let me know and I can add it.