-3

Currently myLeadTrigger code is -

trigger myLeadTrigger on Lead (before update, after update) {
     if(myLeadHelper.firstRun){
          myLeadHelper.firstRun = false;
          if(Trigger.isUpdate && Trigger.isBefore) {
               system.debug('beforeupdate ------');
          }
    
          if(Trigger.isUpdate && Trigger.isAfter) {
               system.debug('afterupdate  ------');
          }
     }
}

and myLeadHelper code is -

public class JLRE_LeadHelper {
    public static boolean firstRun = true;
}

I have also Lead Assignment rule in use. So when I create the Lead record, only one of the trigger context fires. So in the debug logs, I get - beforeupdate ------

So if I remove the line - if(myLeadHelper.firstRun){} my code runs perfectly. But I need to be sure that trigger does not falls into recursion. How can I achieve this ?

2
  • @OleksandrBerehovskyi Yes it may help, but I'm not able to grasp it completely. If you could simplify and answer in my scenario, it would be more beneficial. Sep 8 at 14:42
  • Both before and after will fire...
    – user61140
    Sep 8 at 15:00
0

It's important to note the difference between recursion and multiple calls. Recursion is a problem where you end up in a potentially infinite loop. For example, you have a contact trigger (e.g. Alice) that updates the account (e.g. SpaceWorks), and the account trigger that updates contacts (including Alice), which then updates the account (SpaceWorks), and so on until governor limits are reached. This may happen with two, three, or more objects in a chain, which can get hard to predict, which is why sometimes the only choice is a recursion blocker.

However, there can also be multiple calls to a trigger that are legitimate. This includes using Database.update(records, false), which allows for partial retries, there can be Process Builders, Record-Triggered Flows, and Workflow Rules that can cause a second pass over existing records, there can be an Apex DML operation with a list of more than 200 records, and there can be multiple updates in the same Apex transaction, plus possibly other esoteric scenarios I'm not thinking of at the moment.

So, first consider if you can write your code to avoid recursion without resorting to this technique. For example, I stated in a previous answer that you could use a "rising edge" trigger, which is electrical engineering terminology that means "when a condition goes from false to true", such as when a field changes and now meets certain criteria (and never at any other time). This typically solves most forms of recursion problems.

If you still are having problems and must resort to this technique, you can use the following:

public class myLeadHelper {
    public static boolean willBeRecursive = false;
}

trigger myLeadTrigger on Lead (before update, after update) {
     if(!myLeadHelper.willBeRecursive){
          myLeadHelper.willBeRecursive = true;
          if(Trigger.isUpdate && Trigger.isBefore) {
               system.debug('beforeupdate ------');
          }
    
          if(Trigger.isUpdate && Trigger.isAfter) {
               system.debug('afterupdate  ------');
          }
          myLeadHelper.willBeRecursive = false;
     }
}

By blocking recursion only as long as trigger is in context, this prevents infinite recursive loops while still supporting all other types of non-recursive multiple calls, such as those listed above. You should consider even this as a last resort, because the need to do this means that there's potentially faulty logic in your trigger code.

In some cases, you may have a scenario where records of the same type may be updated in sequence, such as when a Contact updates an Account, which in turn updates other Contacts as well. If you need to consider this level of complexity, a Boolean no longer works, and you need a very slightly different version:

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

trigger myLeadTrigger on Lead (before update, after update) {
     if(!myLeadHelper.containsAll(Trigger.newMap.keySet())) {
          myLeadHelper.willBeRecursive.addAll(Trigger.newMap.keySet());
          if(Trigger.isUpdate && Trigger.isBefore) {
               system.debug('beforeupdate ------');
          }
          if(Trigger.isUpdate && Trigger.isAfter) {
               system.debug('afterupdate  ------');
          }
          myLeadHelper.recordsInTrigger.removeAll(Trigger.newMap.keySet());
     }
}

Again, like the example before, we want to allow partial retries, etc, so we always remove at the end, whatever we add at the beginning, to make sure that we don't break partial updates and other scenarios.

2
  • The use of a single boolean flag is an anti-pattern. Please remove that and suggest use of an alternative, like remembering the records already seen.
    – Phil W
    Sep 8 at 17:58
  • @PhilW It's conditional, really. Without a concrete org to check against, this may be acceptable, or not. But you're right, I can add in another alternative.
    – sfdcfox
    Sep 8 at 18:03

Not the answer you're looking for? Browse other questions tagged or ask your own question.