0

I have a requirement where I need to send a custom object to an external system. The records are usually created in bulk so I have a queueable apex class called from a trigger that loops through the create record and sends each one to the endpoint, when the callout limit is reach I enqueue another job with the remaining.

This is working perfectly well, in fact too well as it is sending more than 250 requests per minute to the other system which is creating a problem.

The system needs to receive a maximum of 100 requests per minute and there is no option for bulk integration, it has to be one at a time.

Is there any way, other than building a middleware where I can space out the queued jobs? I thought of scheduling a job for a minute in the future that calls the queueable class again but I'm not sure if there is a better scenario.

Any input will be appreciated.

Thanks

2

2 Answers 2

3

Salesforce doesn't provide us any real tools when it comes to waiting/rate limiting inside of an Apex class, and the delay between chained queueable calls is not configurable (and worse, it's non-deterministic and also has throttling behavior).

Pretty much any method we can use to do our own rate limiting is going to be rather brute-force.

The safest/simplest approach here would probably be to space out the time between each callout to 600ms (to ensure you cannot go over 100 calls/minute) by using a busy loop.

Something like

public void wasteTime(Integer milliseconds){
    // Datetime doesn't allow us to add milliseconds, but getTime()
    //   returns milliseconds since unix epoch
    Long targetTimestamp = Datetime.now().getTime() + milliseconds;

    while(Datetime.now().getTime() < targetTimestamp){
        // do nothing of importance
    }

    return;
}

Make a callout, do your processing, call the method before the end of the loop you're making your callouts in.

2
  • re: Spring 22 throttling behavior - a tantalizing item on Twitter from PM fishofprey
    – cropredy
    Commented Feb 15, 2022 at 20:08
  • I wrote a similar thing for a multiplexed callout system. P.S. while(cond); works as well, you don't need to {}.
    – sfdcfox
    Commented Feb 16, 2022 at 3:17
1

I suggest this algorithm:

  • create a checkbox on your object (for example, Sent__c).
  • create a batch class that allows callouts and query all records with Sent__c = false and LIMIT 100. In Execute method send these records to your external system and update your checkbox to true.
  • create scheduler that runs once in a minute and executes your batch class (also I suggest to expand running window to 2-3 minutes and querying for not finished batch jobs just in case of long-running update in batch or batch staying in Apex Jobs queue).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .