Monday, June 10, 2013

Saleforce HTTP callouts limit workaround

I need to do tons of requests to an external service that, unfortunately, doesn't allow me to put multiple action requests within one single HTTP request, so that each action I want to send to this external service I have to do an HTTP request. Problem: Salesforce allows you to do only ten HTTP requests per execution. I could use Batch Jobs to schedule all the requests I need, but Batch Jobs are executed when resources are free, and I want to have the requests to be sent almost in real time, not "when Salesforce has time to do it".

So, here's the workaround. The key is that the limit is "per execution", and an AJAX call (done through a standard Visualforce <apex:actionFunction>) is actually a single execution. I can "loop" in Javascript to do requests as long as I need it.

Let's have a look at the code.

The controller:
public with sharing class testJavascript {
 public String requestStatus { get; set; }
 public String requestMore { get; set; }
 public Integer requestNumber { get; set; }
 public Integer requestCurrent { get; set; }
 public testJavascript () {
  requestStatus = '';
  requestMore = '';
  requestNumber = 10000;
  requestCurrent = 0;  
 }
 public void doRequest () {
  if (requestCurrent <= requestNumber) {
   Http http = new Http();
   for (Integer startPoint = requestCurrent; (requestCurrent <= requestNumber) && ((requestCurrent - startPoint) < 10); requestCurrent++) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint('http://www.google.com');
        req.setMethod('GET');
    HTTPResponse res = http.send(req);
   }
   requestStatus = requestCurrent + ' out of ' + requestNumber + ' processed';
  }
  if (requestCurrent >= requestNumber)
   requestMore = 'false';
  else requestMore = 'true';
 }
}

The page:
<apex:page controller="testJavascript">
<apex:form>
 <apex:outputpanel id="status">
  Status:

  {!requestStatus}
  <script>requestContinue = {!requestMore};</script>
 </apex:outputpanel>
 <script>
  function requestMore() {
   if (requestContinue)
    doRequest();
  } 
 </script>
 <button onclick="if (doRequest()) return false; else return false;">Start</button>
 <apex:actionfunction action="{!doRequest}" name="doRequest" oncomplete="requestMore()" rerender="status">
</apex:actionfunction></apex:form>

Some explication:

  1. In the controller I have a request counter (requestCurrent, set to 0 at beginning) and a request amount (requestNumber, set to 10000 at beginning) and a method, doRequest(), that, given those two variables, executes the next 10 HTTP requests (increasing the counter) and updates the status String (requestStatus) and the requestMore String/Boolean, setting it to true if other requests are needed (if the counter is lower than the request amount we need) or false if not.
  2. In the page I have an <apex:actionFunction> pointing to this method, that rerenders the status panel. In the panel I show the status string and I update a Javascript global variable (requestContinue) with the String/Boolean given in requestMore by the doRequest() APEX method.
  3. The actionFunction has an oncomplete attribute that calls another Javascript function, requestMore(), that is in the page code. This function checks for requestContinue value (updated after each rerender): if true calls again the doRequest() actionFunction and 10 more requests are executed, if false it does nothing.
The user has just to push the <button> (that does the first actionFunction call) to start the loop.

Nice, isn't it? :-)

4 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Thats great. There is also a solution which might help you.
    You can make more than 10 callouts by this approach:
    http://techstuffdiary.wordpress.com/2014/02/28/no-callout-limit-and-doing-dmls-before-callout/

    ReplyDelete
  3. This solution is not working for me.I am still getting System.LimitException: Too many callouts: 11

    ReplyDelete

  4. This information you provided in the blog that is really unique I love it!! Thanks for sharing such a great blog Keep posting..
    Salesforce Training in Gurgaon
    Salesforce Course in Gurgaon
    Salesforce Institute in Gurgaon

    ReplyDelete