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".
Some explication:
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.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:
- 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.
- 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.
- 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