As mentioned in a prior blog post, we have eliminated the highly unloved script statement limit.  As a general rule, this will allow you to run more logic within a single transaction.  I hope you are all getting used to your larger digs and trying to figure out what you are going to do with all those extra statements.

One of the benefits to going away from statement counting is a performance lift.  We don’t need to do that pesky “i++” call after every single statement.  While incrementing a counter isn’t very expensive, it’s non-zero, and it’s multiplied by the billions every single day here in the cloud.  Less overhead means faster execution.

The Loose End

This leaves us with one loose end – Limits.getScriptStatements().

Some of you have never heard of this.  If that’s you, you’re in the clear! Feel free to return to cranking out awesome Apex code.

Others of you may have used this in your code as a backstop against hitting the ole’ statement limit.  Perhaps you wrote something like this:

    if (Limits.getScriptStatements() + 1000 < Limits.getLimitScriptStatements()) {
        //do something that takes 1000 script statements
    } else {
        //exit gracefully
    }

This is nice-looking code!  It served a valid purpose, and served it well.  It’s also no longer going to do what it used to do.

As I mentioned, we are no longer counting script statements, because that was taking up actual time and it is no longer used by us internally.  As such, the Limit.getScriptStatements() method is undefined.

What Should We Say?

We had to return some value for this method, despite it being undefined. This is because you’ve used it in your nice-looking code, and we want it to compile.  We had two good options for a return value for this method: we could return zero, or we could return MAX_INT.

Returning zero was a bad option.  Let’s say your nice-looking code looked like this instead:

    while (someFlag && Limits.getScriptStatements() + 1000 < Limits.getLimitScriptStatements()) {
        //do something that takes 1000 script statements
        //maybe set someFlag to false, maybe not
    }

This code is as pretty as the code above, and it will now also not work.  However, if we chose to return zero for the limit call, this loop would be like that Titanic song: it would go on and on.  That song was terrible, and so is an infinite loop – you don’t want either of them to happen to you.  (Note: any opinions on Celine Dion songs are my own and do not reflect Salesforce’s official stance on Celine Dion.)

The alternative is to return a value that is larger than what you thought the limit would be.  This will terminate the loop earlier than you might want, but at least the code will terminate.  This means less infinite looping and less load on our service and thus faster operation for everyone.  However, it appears that there are places where developers have wrapped their entire code in this type of flow control. In these cases, no code is ever going to execute, causing an aging Mick Jagger to start prancing around singing “Start me up!”  (Again, any opinions on an aging Mick Jagger are my own and do not reflect Salesforce’s official stance on the aging process of English rock people.)

Clever Hack

Since returning either of these options is bad, we are going to make a change to the return value.  We are going to convert your cpu usage against the limit into an equal ratio of script statements against the limit.  We are essentially going to mimic the statement counting by using the cpu usage.  Since the cpu timeout is our backstop that replaced script counting for service protection, this is the closest we can get to giving you a fake value that is not dangerous or terminal.

Please keep in mind that this number is not what it says it is.  It is NOT the number of statements.  It is a representation of what the statement count might have been, relative to your limit.  It will, in nearly every situation, undercount the number of statements done. The intention with this mimicry is to allow your code to probably do what it used to do without an immediate failure.

Your Mission, Should You Choose To Accept It…

The purpose of this clever hack is to buy you a little time.  Given that the method’s return value is wrong, and isn’t what you think it is, you should look through your code and do your best to remove calls to this statement. I can’t fix your code for you – there is too much of it!! But I trust you to do the needful.

You can still do flow control in a very similar way!  We have replaced script statement counting with a CPU timeout, so you can track towards that instead of towards statements.  The flow control that I first mentioned could very quickly be rewritten as follows:

    if (Limits.getCpuTime() + 1000 < Limits.getLimitCpuTime()) {
        //do something that takes maybe 850 or 900 milliseconds
    } else {
        //exit gracefully
    }

In the end, regardless of what we chose, you are going to look at your code and say, “Dang, I don’t need this anymore, let me get rid of this!” Or perhaps, “Dang, I should be doing the same thing, but checking the CPU timer!”  Or even, “Dang, that is some good-looking code!”  Either way, you will be safer removing the call to the getScriptStatements method and replacing it with whatever is relevant to your custom logic.

Bookmark the permalink. Trackbacks are closed, but you can post a comment.
  • Chris Bland

    Josh – this is great to hear. Will this perform differently based on the API version of the code being executed?

    • Katia Hage

      The new behavior of getScriptStatements in Spring ’14 applies to all API versions. This is because the script statement limits are no longer counted on the platform for all API versions.

  • Dan Appleman

    Nice solution. When can we expect to see it implemented? At the moment spring 14 is still returning Limits.getLimitScriptStatements as a result to Limits.getScriptStatements…

  • Dan Appleman

    Another note – a design pattern sometimes used with Limits.getScriptStatements was to compare to a fraction of the available limits. Say: if(Limits.getScriptStatements() < Limits.getLimitScriptStatements()/2) – a good way in a non-deterministic app to get an idea if you're running into trouble and might want to start moving things into a future operation. This solution is perfect for anyone who is already testing against a fraction of the available limits for the context instead of a hardcoded script number.

  • Maroš Sitko

    I do not know, how many users use something like you in your examples. But we used it in our test class, where we tested bulks on triggers with this line :
    system.assert(Limits.getScriptStatements()*100 / Limits.getLimitScriptStatements() <= 90);
    when someone create wrong trigger, which can reached limits, test class fail and we know that something
    is wrong before user get error.
    I think, that more users used getScriptStatements in this way – they wanted to be informed about possible reaching limits before user get error. So I thing, that getScriptStatements should return 0 instead of MAX_INT. In this case less users should fix their codes.