[SalesForce] Third party API has callout time limits: how to catch with error handling, and how to control callout timing

The third party API I'm working with (Act-On, a marketing software), has a limit of 5 callouts per minute in their sandbox. Unfortunately for me, some of my code requires that I loop through a series of callouts to their API, and eventually I get this for my JSON body:

<amt:fault xmlns:amt="http://wso2.org/apimanager/throttling">
<amt:code>900800</amt:code>
<amt:message>Message Throttled Out</amt:message>
<amt:description>You have exceeded your quota</amt:description></amt:fault>

My question has two parts. First off, I only saw this error when I used system.debug on the JSON body. The following code using the CalloutException didn't catch this error:

        try {
            res = http.send(req);
        } catch(System.CalloutException e) {
            System.debug('Callout error: '+ e);
        }

I suppose I could write my own error checker now that I know what message will be returned, but why didn't CalloutException catch it? My guess is that the callout was successful in a strict sense, it was just the JSON body that was no good… in which case, should I be using JSONException instead?


The second question is, how do I regulate my callouts to conform to the time limit imposed by this API? I don't need the code the execute quickly or anything (this will be a scheduled apex class), but I'm not exactly sure how to say in apex "wait 60 seconds, then do this".

I've seen posts online that offer workarounds to accomplish this (eg run a while loop tied to a millisecond counter), usually accompanied with replies warning that it would trigger governor limits. I've also read that it can be done in VF, but not in apex. I hope that last part isn't true!

Best Answer

The fault may be accompanied by a 500 status code (for SOAP that is likely to be the case - see 6.2 SOAP HTTP Response - but I guess the API you are calling isn't SOAP as you mention JSON) so your code could do this:

res = http.send(req);
if (res.getStatusCode() < 500) {
    // Process a non-fault response (JSON?)
} else {
    // Process the fault response (XML?)
}

Worth checking (e.g. by using System.debug) because it is a simple way to tell the difference between the two cases.

On throttling your requests, Apex does not have any sleep mechanism and if you attempt to run a busy wait you will exceed the CPU governor limit (after 10 seconds).

I believe you can schedule a job for say 1 minute in the future and when that runs schedule another job for a minute later. (I have not tried that though.) Note that there is no guarantee that the job will run at a specific time as the platform reserves the right to delay when busy. Perhaps someone with experience of using scheduled Apex in this way will provide a definitive answer on the viable patterns and the rates they achieve.

(From 2 years ago: Are there best practices to get scheduled apex scheduled to run faster than once per hour?.)

Related Topic