What is Recursive Trigger in Salesforce?


A recursive trigger in Salesforce is one that performs an action, such as an update or insert, which invokes itself owing to,  say something like an update it performs.

Recursion is the process of executing the same task multiple times. There may be chances to hit the Governor Limit with Recursive Trigger. Below example shows what is a Recursive Trigger and how it can be avoided.

4fLbv

How to avoid Recursive Trigger in Salesforce?


To avoid recursive triggers you can create a class with a static Boolean variable with default value true. In the trigger, before executing your code keep a check that the variable is true or not. Once you check make the variable false.

This is a simple way to create this error via a trigger on an object called Test__c…

With the above trigger in place, when one Test__c object record is created by the user, the trigger executes and then inserts another record of the same type, which causes the trigger to execute again for this record, this keeps repeating until the platform stops things itself. As you can see by this screenshot the platform tolerates up to 8 levels before it stops.

This also applies to other DML operations such as updating or deleting from the same object. Typically you encounter this scenario when you have some kind of hierarchy relationship within your object, such as a parent child and you need to update parent records when child records are effected. There is a good summary in the Context Variables Considerations of what can and cannot be done.

Avoiding Recursive Triggers

The Apex Developers Guide surprisingly does not say much about this, aside from a reference in the Static and Instance topic.

Use static variables to store information that is shared within the confines of the class. All instances of the same class share a single copy of the static variables. For example, all triggers that are spawned by the same transaction can communicate with each other by viewing and updating static variables in a related class. A recursive trigger might use the value of a class variable to determine when to exit the recursion.

Suppose you had the following class:

The above example would be adapted to use this approach as follows…

Static variables defined in a trigger don’t retain their values between different trigger contexts within the same transaction, for example, between before insert and after insert invocations. Define the static variables in a class instead so that the trigger can access these class member variables and check their static values.

With this approach in place the recursion stops once the trigger is called a second time, as it does not attempt to insert a third record. The result is for every one record a second additional record is created and the recursion is avoided.

Warning: Any form of recursive coding is by definition complicated, as this blog I found illustrates the use of a static flag recording if the trigger has previously been executed can be to simplistic for some use cases, if you don’t fully consider your use cases.

Best practice for triggers:

  1. One trigger per object so you don’t have to think about the execution order as there is no control over which trigger would be executed first.
  2. Logic-less Triggers – use Helper classes to handle logic.
  3. Code coverage 100%
  4. Handle recursion – To avoid the recursion on a trigger, make sure your trigger is getting executed only one time. You may encounter the error : ‘Maximum trigger depth exceeded’, if recursion is not handled well.

Here’s an example of code using Static Set to avoid recursion.

Class

public class checkRecursive {
     public static Set<Id> SetOfIDs = new Set<Id>();
}

Trigger

trigger TestTrigger on Account (before insert) {
    if (Trigger.isAfter && Trigger.isInsert) {
        List<Account> accList = new List<Account>();
      for (Account test: Trigger.new) {
          If(!checkRecursive.SetOfIDs.contains(test.Id)){
              test.Name = 'helloworld';
              accList.add(test);
            checkRecursive.SetOfIDs.add(test.Id);
          }
      }
      insert  accList;
    }
}

Static in Salesforce are per transaction, so the value will be true only for the current transaction. It will be initialized to true for other transactions. Don’t think of static in Java term where static values persist till the class is loaded into memory.

Reference: https://help.salesforce.com/articleView?id=000332407&type=1&mode=1