0

It may be a simple question but I am not able to understand it clearly.

This is a paragraph of Salesforce documentation Here is the link:
Apex Transaction Governor Limits

Recursive Apex that doesn’t fire any triggers with insert, update, or delete statements, exists in a single invocation, with a single stack. Conversely, recursive Apex that fires a trigger spawns the trigger in a new Apex invocation. The new invocation is separate from the invocation of the code that caused it to fire. Spawning a new invocation of Apex is a more expensive operation than a recursive call in a single invocation. Therefore, there are tighter restrictions on the stack depth of these types of recursive calls.

I am not able to understand this paragraph clearly. What does Recursive Apex exactly mean here and when new transaction is invoked from the same Apex transaction.

1 Answer 1

4

Terminology is important in this case. Invocation != transaction.

Recursion is code that calls itself, e.g.

public void countDown(Integer num){
    // The "base case", the thing that stops our code from calling itself again
    if(num <= 0){ return; }
    
    system.debug(num);

    // The recursion step (calling the method from within the method)
    // Since the recursion step is the last thing being done, this is "tail recursion"
    //   or a "tail call" (though not all "tail calls" are recursive)
    countDown(num - 1);
}

As the documentation states, recursive code like that (no DML) can be handled by just pushing more "frames" onto the stack. The "stack" is a low-level code/hardware concept that gets used when you call methods. The arguments and the memory address that the cpu should return to after the method is done executing are stored on the stack.

Recursion (especially tail recursion) is a generally cheap/fast, and simple optimiztations exist. As a result, Salesforce isn't too concerned about the recursion depth (how many times the method calls itself).

Things change when you have DML. Every time you perform DML, Salesforce creates/starts a new invocation contained within the current transaction. What exactly an "invocation" is isn't terribly important to us, all we need to know is that it takes more resources (compute, database, memory, whatever) and that's why Salesforce has a strict limit on it.

The limit is placed on DML that happens within a trigger. Adding a DML call to my example above isn't sufficient to cause Salesforce to stop execution.

It's not clear whether

  • this is strictly for recursive cases (so things like an account that updates itself again in the trigger)
  • if "recursion" is defined as "dml on the same object" (e.g. an Account updating a parent Account),
  • or if it's broader and includes any dml inside of a trigger (e.g. OpportunityLineItem updates Opportunity, updates Account, updates a parent Account, etc...)

It's hard to test the third possibility (you'd be more likely to run into some other limit first). The second possibility is also not easy to test because it's not really common to have record hierarchies that deep.

When people run into this limit, it's most likely the first possibility (and a result of unintentional or unchecked recursion).

4
  • Now things are pretty cleared. One question, can new transaction can be started by some way from the same transaction that is currently running?
    – riseAJdev
    Commented Dec 19, 2022 at 16:17
  • @riseAJdev yes, but only through asynchronous execution (@future, queueable, batchable, schedulable). Also, emphasizing one more time, an invocation is different from a transaction. I think sfdcfox put it well when he said "1 debug log = 1 transaction".
    – Derek F
    Commented Dec 19, 2022 at 16:23
  • Okay, I got it. Thanks!
    – riseAJdev
    Commented Dec 19, 2022 at 16:55
  • N.B. publishing platform events is another example of async
    – cropredy
    Commented Dec 19, 2022 at 19:14

You must log in to answer this question.

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