0

I have a trigger that is hitting the 16 depth limit. I may not understand how the trigger works. I'm fairly confident that the classes and methods I have are not recursive. They work fine, but I have created a new class and I want to add it to the after update section, and this is when I hit my limit.

My classes do not have any queries in for loops.

As an aside, and I am not sure this is related or not, but our external vendors are telling me they occasionally get timeouts for their API connections. Could some recursion cause the timeout? Or is that completely unrelated?

Should I separate out my trigger to before/after triggers? Have multiple triggers on my core objects?

I have tried to create a recursion prevention based on some code I have looked up. Most of the related links seem to be for recursion prevention, and I am just not sure that is what I need?

I have been told about how triggers could be used to control other triggers, but I don't understand that well enough to implement. I found one example that actually kind of makes sense to me: using classes to run the actual classes I want. Could this help?

I just don't think our trigger is that complicated. There must be a simple solution.

Here is my trigger:

Trigger

trigger leadTrigger on Lead (before insert, after insert, before update, after update) {
    Lead[] newLead = trigger.new;
    Lead[] oldLead = trigger.old;

    //prevent recursion and trigger depth
    if(recursionControl.leadProcessed == true) return;
        recursionControl.leadProcessed = true;

    if(trigger.isInsert){
        //static variable to define creation of leads - be careful in bulk uploads
        leadNewLeadTransaction.isInsert = true;
    }

    if(trigger.isbefore){

        //always trigger

        //Clean up the phone fields
        method();

        //update field
        method;

        if(trigger.isInsert){
            //grab information from parent
            method();

            //Assign out to the floor if needed
            assignMethod();

            //sets record type
            method();
        }

        if(trigger.isUpdate){
            //Check to see if the owner was changed to a queue and assign accordingly
            if(owner changed) method();
        }
    }

    if(trigger.isafter){//----------------------------------------------------------------After
        //always run

        if(trigger.isInsert){
            //add child on insert
            method();

            //future method to do callout
            method();

            //send email if insert
            method();

        }
        if(trigger.isUpdate){
            //convert lead            
            customConvert();

            //THIS IS THE ONE THAT FAILS EVERY TIME
            method();
        }
    }
}

recursionControl

public class recursionControl {
    public static boolean leadProcessed = false;
    public static boolean oppProcessed = false;
    public static boolean taskProcessed = false;
    public static boolean complianceProcessed = false;
    public static boolean inqProcessed = false;
    public static boolean indEmailProcessed = false;
}
5

Using boolean flags is often something of a bodge. As well as stopping the undesired unlimited recursion, it can stop the logic from settling to the correct values. Best to first think through the sequence of inserts and updates and aim to eliminate the recursive cases.

A simple cause of the recursion limit problem is updating the object - making a DML update call - that the trigger is running on. That just causes the trigger to be called again, the update to be repeated and so on until the recursion limit is hit. Instead, make changes only the before phase, and let the platform to the update. Problem solved.

Often multiple objects are involved. For example, an update of A causes an update of B, and an update of B causes an update of A. Once again, repeated updates until the recursion limit is hit. A clean way to handle this is to only do the update if it is needed i.e. check if the field is already set to the correct value and if it is don't do the update. Then the first update of A is done, then the first update of B is done, but after that, no more updates are done. Problem solved. Code like this can help:

 for (MyObject o : Trigger.new) {
     MyObject old = Trigger.oldMap.get(o.Id);
     if (old.MyField != requiredValue) {
         // Change needed
     } else {
         // No change needed
     }
 }

And to quote cropredy's comment from below (a point I hadn't thought of):

boolean flags are problematic when transaction size is > 200 records such as in Platform Event, Bulk API, or straight DML as the trigger on records 201+ will end up doing nothing

But realistically, many orgs get into a giant tangle where no-one knows all the interactions, so that is when boolean flags in Apex classes (or sets of Id values) become the brute-force work-around.

  • I do this in each of my classes. Perhaps that is not enough? Should I be doing this in the trigger? Your example of A updating B updating A is likely the problem, but I am finding that hard to find. And I'm struggling identifying where that may be. Is there any way to identify when this happens? Any tools that show performance other than the debug logs? – Chance Jun 24 at 15:37
  • 1
    @Chance I've just used the debug logs for this. There is the additional problem that e.g. workflows can also interfere or triggers written by other teams. As long as you are clear what the code is doing it can be in the trigger or in a separate class: you do need to pass in e.g. Trigger.oldMap if the logic is in a class through. – Keith C Jun 24 at 17:28
  • 1
    +1 for "bodge" - @Chance : boolean flags are problematic when transaction size is > 200 records such as in Platform Event, Bulk API, or straight DML as the trigger on records 201+ will end up doing nothing – cropredy Jun 24 at 21:23
  • Hi @cropredy, Gret point that I never thought of that and have quoted you in an edit to the answer. – Keith C Jun 25 at 7:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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