[SalesForce] Best way to avoid trigger recursion as using static boolean variable processes only first 200 records

What is the best way to avoid recursion of trigger ?

Below are the approaches used and problems faced

Using static boolean variable from handler class

Apex Class

public Class checkRecursive{
    private static boolean run = true;
    public static boolean runOnce(){
        if(run){
            run=false;
            return true;
        }else{
            return run;
        }
    }
}

Apex Trigger

trigger updateTrigger on anyObject(after update){
    if(checkRecursive.runOnce()) {
        //write your code here            
    }
}

Using the above approach works only for the first chunk of records i.e. first 200 records, post first 200 records, trigger does not work i.e. lets say, I am trying to insert 400 records, so trigger will segregate this 400 records into 2 chunks and when the first batch runs, variable is set to false and hence for the second batch i.e. next 200 records are not processed (Variable is not reset between chunks).

Using static set variable from handler class

We can use this static set approach, but I am not sure how to handle this when we are working with before insert context i.e. when Id is not generated and when we don't want to check for duplicates.

Came across this help documentation from Salesforce Apex Trigger Best practices to avoid Recursion which shows how to use static set<Id> to prevent recursion, but I suppose the example which is shown is incorrect.

Apex Class

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

Apex 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;
    }
}

In the above example from Salesforce help link mentioned above, trigger is registered for before insert event whereas it is checking for after insert context variables i.e. Trigger.isAfter && Trigger.isInsert, so not sure how should it be handled when this check needs to be done for before insert context or Do we really need to check for recursion for before insert context ?

Addition

If we don't add a check for recursion for INSERT event, the trigger will fire multiple times i.e. 2 times in a case where workflow field update fires on record insert which will re-run any before and after insert triggers again—as insert triggers. Triggers and Order of Execution

Best Answer

If you want to avoid recursion the set of ids is the right way.

  1. Before anything else, filter the chuck of records by their id and keep only the ones not present in the set or that do not have an id yet.
  2. Update the set of ids.
  3. Do anything you have to do in your before trigger.
  4. If your trigger handles also inserts, update again the set of ids
  5. Do anything you have to do in your after trigger.

Note also that:

  • You can use a map if you want to enable the recursion of some records until a certain depth is reached.
  • You can use multiple sets and maps to handle the recursion of different records in different ways.
  • You can avoid to filter the chuck of records if it is a delete trigger to permit the deletion of the records even if it is updated/inserted in the same transaction.
Related Topic