7

As we know (as of V46), there is no apex sleep method. Various workarounds have been proposed such as doing a callout to a service with platform support for sleep but this makes unit testing complicated not to mention callout-dml sequencing to consider.

Simple sleep loops such as this Util.cls method:

public static void sleep(Integer secs) {
    Long epochToDate = System.currentTimeMillis();
    Long epochStop = epochToDate + (secs * 1000);

    while (epochToDate <= epochStop) {
        epochToDate = System.currentTimeMillis();
    }
}

run the risk of blowing up CPU limits (10 secs) for the transaction.

What is the CPU penalty of the aforementioned code sample?

2 Answers 2

9

Some earlier experiments under versions 45 and below had suggested that CPU time was 1-5% less than elapsed time - so if you wanted to delay by 5 secs, the CPU consumed would be somewhere between 4.75 : 4.95 CPU secs

But I retried in V46 using this simple testbed:

Integer delaySecs = 15
Long start = System.currentTimeMillis();
Integer cpuStart = Limits.getCpuTime();
Util.sleep(delaySecs);
Long stop = System.currentTimeMillis();
Integer cpuStop = Limits.getCpuTime();
System.debug(LoggingLevel.INFO,'elapsed delta:' + (stop-start));
System.debug(LoggingLevel.INFO,'cpu delta:' + (cpustop-cpustart));

And got these results (V46)

delaySecs (input) elapsed (result) cpu (result)
   18                 18.003         10.020 (over limit)
   17                 17.002          9.304
   16                 16.003          9.265
   15                 15.004          8.552
   14                 14.017          8.001
   13                 13.002          7.231
   ...
   10                 10.003          5.431
   ...
    5                  5.020          2.812
    4                  4.002          2.298
    3                  3.016          1.724
    2                  2.016          1.146
    1                  1.033          0.586  

YMMV and there's no guarantee that SFDC won't change the underlying implementation of System.currentTimeMillis() to be closer 1:1 with CPU time.

How might this be useful?

  • Implementing a variable backoff delay (jitter) in asynchronous queueable transactions that lock on a common resource. See this stackexchange q&a for example. Consider t concurrent queueable async transactions, all locking on the same resource. Randomly backoff by n secs ( n < 17) each transaction by sleeping, then requeueing the queueable.

By way of example, transaction 1 might back off by 3 secs, transaction 2 by 12 secs, transaction 3 by 1 sec, etc and when their backoff queueable job starts anew, they may be less likely to contend on a shared resource. Hence you have a range greater than 10 (secs) to introduce jitter delays.

You of course might need a sleep delay < 17 secs if the async transaction has already consumed a bunch of CPU before hitting some shared resource lock contention exception.

2

Why are you looking to 'sleep' and for how long? Tying up resources in a tight loop does not seem like the ideal solution.

Something that I did to get a 'job' to run at faster intervals than can be scheduled and to actually run when they are called (versus trying to use the Apex scheduler and hoping that it runs when you want it to) was to make the method a REST endpoint and then have an external program (on an external system) call the REST endpoint (via local cron) on a scheduled basis. Sure, it uses up an API call per invocation, but, because it is a synchronous REST call, Salesforce runs it immediately when you call it (and no matter how often), so it gets around the timing limitations (at least for me it does).

May not solve your use case, but just tossing the idea out there in case.

1
  • use case was multiple concurrent queueables doing a Select for Update on a shared resource and getting an UNABLE_TO_OBTAIN_LOCK error; was investigating [this algo(aws.amazon.com/blogs/architecture/…) as mitigation.
    – cropredy
    Jul 2, 2019 at 20:59

You must log in to answer this question.

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