Handling recursion in Apex Triggers

Handling recursion in Apex Triggers and the best practices related to it.

What is a Recursive Trigger?

A recursive trigger performs an action, such as an update or insert, and then invokes itself as a result of, say, an update.

How to avoid Recursive Triggers?

To avoid recursion on a trigger, ensure that your trigger is only executed once. If recursion is not handled properly, you may receive the error: 'Maximum trigger depth exceeded'.


1. Use Static Boolean Variable

In an Apex class, you can use a Static Boolean variable and check the variable in an Apex Trigger. If it is true, run your logic to make it false so that the trigger cannot be executed again.


Apex Class 

public class CheckRecursionUtility {
     Public static Boolean firstcall = true;
}

Apex Trigger 

Trigger contactTrigger on contact (after update) {

    if(CheckRecursionUtility.firstcall) {
CheckRecursionUtility.firstcall = false;
//write your code here - invoke handler/helper class method     } }

Static in Salesforce is per transaction, so the value will be true only for the current transaction. It will be initialized to true for other transactions.

UPDATE

While the above approach is good for less number of records (<200 records). You should only use this as a last resort because the need for it indicates that your trigger code contains potentially faulty logic.

2. Use Static Set to Store Record Id

So instead of using the Static boolean variable, we can use Set to Store the Ids. And in execution we can check if we have already processed those records then we can skip them else we will process them.

Apex Class 

public class CheckRecursionUtility {
    public static Set<Id> recordsInTrigger = new Set<Id>();
}

Apex Trigger 

Trigger contactTrigger on contact (before update, after update) {
    if(!CheckRecursionUtility.recordsInTrigger.containsAll(Trigger.newMap.keySet())) {
          CheckRecursionUtility.recordsInTrigger.addAll(Trigger.newMap.keySet());
          if(Trigger.isUpdate && Trigger.isBefore) {
               system.debug('beforeupdate ------');
          }
          if(Trigger.isUpdate && Trigger.isAfter) {
               system.debug('afterupdate  ------');
          }
          CheckRecursionUtility.recordsInTrigger.removeAll(Trigger.newMap.keySet());
    }
}

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
  5. Context-Specific Handler Methods - Create context-specific handler methods in Trigger handlers

Comments

  1. This is not the most optimum solution to avoid Recursion, If there are more than 200 records updated in Bulk, The Trigger will run for first 200 records and will not run for the other 200. In a way it stops recursion but will disrupt the functionality.

    ReplyDelete

Post a Comment

Popular posts from this blog

Introducing Lightning Record Picker: A New Era of Record Selection

New Intelligence View for Leads and Contacts in Salesforce | Winter '24