Tuesday, August 13, 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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';
 }
}
1
 
The page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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? :-)

No comments :

Post a Comment

Labels

visualforce page ( 13 ) apex integration ( 5 ) apex trigger ( 4 ) csv file from vf page ( 4 ) javascript ( 4 ) csv visualforce page ( 3 ) Too many ( 2 ) call out ( 2 ) integration ( 2 ) rest api ( 2 ) salesforce rest api ( 2 ) salesforce to salesforce integration ( 2 ) sfdc rest api ( 2 ) trigger ( 2 ) 15 digit to 18 digit ( 1 ) DML rows in Apex ( 1 ) Date Conversion ( 1 ) Date/Time conversion ( 1 ) Deploy ( 1 ) Objects to Future Annotated Methods ( 1 ) SFDC limits ( 1 ) Sobject to Future Annotated Methods ( 1 ) Test Class ( 1 ) TimeZone Conversion ( 1 ) Too many dml rows ( 1 ) Too many future calls ( 1 ) annotations ( 1 ) apex code ( 1 ) closed opportunities ( 1 ) commit ( 1 ) convert ( 1 ) create records ( 1 ) csv create records ( 1 ) custom setting ( 1 ) deployment ( 1 ) deployment changeset ( 1 ) disable apex class ( 1 ) disable apex trigger ( 1 ) disable in production ( 1 ) document ( 1 ) download ( 1 ) field name ( 1 ) formula fields ( 1 ) iframe ( 1 ) inactive ( 1 ) intellisense ( 1 ) jsforce ( 1 ) limits ( 1 ) matrix report in vf page ( 1 ) multi select ( 1 ) multi select salesforce ( 1 ) multiselect ( 1 ) paypal ( 1 ) picklist ( 1 ) record type ( 1 ) rollback ( 1 ) salesforce limits ( 1 ) salesforce list ( 1 ) salesforce map ( 1 ) salesforce rest ( 1 ) salesforce set ( 1 ) salesforce1 ( 1 ) sandbox deployment ( 1 ) sfdc collection ( 1 ) sfdc list ( 1 ) sfdc map ( 1 ) sfdc rest ( 1 ) sfdc set ( 1 ) uncommitted ( 1 ) updated field ( 1 ) user ( 1 ) validation rule opportunity ( 1 ) validation rules opportunities ( 1 ) vf page ( 1 )

Ad