Monday, October 28, 2019

How to avoid recursive trigger in Salesforce?

A trigger is a piece of code which executes when operation such as before or after insert/update/delete
is done on a record. As we can perform update using tools like workflow, process builder there is a possibility of same piece of trigger code can running again and again on updates from one or the other tool. The recursive trigger is a trigger which call itself repeatedly and leads to infinite loop and hence there can be a chance we hit the governor limit.

Recursion is process of executing the same tasks multiple times. Recursion can results in unexpected output or error, so to avoid recursive behavior of trigger we make use of a static variable in Salesforce.

Let us understand how we should write our code to avoid recursion.

In below example based on phone number update on account, we will update all related contact records with phone number from account.

Trigger:

trigger Accounttrigger on Account (after update) {

      if (Trigger.isAfter && Trigger.isUpdate) {

        List<Account> accList = new List<Account>();

        List<Contact> conList= new List<Contact>();

      for (Account acc: Trigger.new) {

          If(!checkRecursiveApexClass.accIdSet.contains(acc.Id)){

              If(Trigger.newmap.get(acc.Id).phone!=Trigger.oldmap.get(acc.Id).phone){

              for (Contact con: [SELECT id from contact where accountid=:acc.id]) {

               con.Phone=acc.phone;

               conList.add(con);

              }

              }

            checkRecursiveApexClass.accIdSet.add(acc.Id);

          }

      }

      if(conList.size() > 0){

         update conList;

      }

    }

}


Apex Class:

public class checkRecursiveApexClass{

 public static set<id> accIdSet=new set<id>();

}


We can also make use of boolean static variable as shown below however there is a problem with this approach when we have more than 200 records which cause the trigger to fire as shown below.

As we know trigger executes on batches of 200 record at a time.

Suppose we are inserting 240 records, so in this case trigger will fire twice once for 200 records and once for 40 records and suppose we have controlled trigger recursion using boolean static variable so our logic will work for first 200 records and remaining 40 records will get skipped.

Trigger:

trigger Accounttrigger on Account (after insert) {

      if (Trigger.isAfter && Trigger.isInsert) {

        List<Account> accList = new List<Account>();

        List<Contact> conList= new List<Contact>();

          If(checkRecursiveApexClass.firstRun){

             system.debug('Trigger is in if block and record size is'+trigger.new.size());

             checkRecursiveApexClass.firstRun=false;

          }

          Else{

             system.debug('Trigger is in else block and record size is'+trigger.new.size());

          }

    }

}


Apex Class:

public class checkRecursiveApexClass{

 public static boolean firstRun=true;

}


How to avoid recursive trigger in Salesforce?

2 comments:

  1. what would happen the next time trigger is invoked? If the value is already set to false.

    ReplyDelete
  2. 1: When Reset of boolean variable occurs
    2: What if Upsert operation in progress for bunch of data, how boolean variable works?

    ReplyDelete