function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ChickenOrBeefChickenOrBeef 

Trigger no longer working now that I'm checking for recursion

Hello everyone,

I made a thread on here a few weeks ago about how I couldn't deploy a new trigger, because a previous 'After' trigger I deployed was causing too many SOQL queries in my new 'Before' trigger.

Anywho, a fine gentleman on here told me I needed to check the aforementioned 'After' trigger for recursion, so that it wouldn't run more than once. That allowed me to deploy the new 'Before' trigger.

So what is the problem now? That 'After' trigger that I'm checking for recursion....it doesn't work anymore. I only checked today to see if it was still working, but it seems it hasn't been working since I made that change to the code. When I remove the recursion check and test out the trigger in the sandbox, it works again.

Why do I think this is? Because the purpose of that 'After' trigger is to update another opportunity (the same object). I'm assuming it won't work if it only runs once. Perhaps I have to run it twice? If so, how can I make that change? Please keep in mind that I'm still a newb to coding.


Here is the class I'm using to check for recursion:

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




Here is the trigger that no longer works:

trigger RenewalProcess on Opportunity (after insert, after update) {
   
     if(checkRecursive.runOnce()){
   
   Set<String> allOpps = new Set<String>();
    for(Opportunity renewalOpp : Trigger.new) {
        if (renewalOpp.Renewed_Opportunity__c != null) {
            allOpps.add(renewalOpp.Renewed_Opportunity__c);
          }
    }

    List<Opportunity> potentialOpps = [SELECT Id FROM Opportunity WHERE Id IN :allOpps];

    Map<String,Opportunity> opportunityMap = new Map<String,Opportunity>();
        for (Opportunity o : potentialOpps) {
            opportunityMap.put(o.id,o);
        }
   
    List<Opportunity> firstOppsToUpdate = new List<Opportunity>();

        for (Opportunity renewalOpp : Trigger.new) {
             if (renewalOpp.Renewed_Opportunity__c != null) {
             Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
             renewedOpp.Renewal_Process_Checkbox__c = TRUE;
             firstOppsToUpdate.add(renewedOpp);
           }
           
        }

    update firstOppsToUpdate;
     
     List<Opportunity> oppsToUpdate = new List<Opportunity>();
       
        for (Opportunity renewalOpp : Trigger.new) {
            if (renewalOpp.Renewed_Opportunity__c != null && renewalOpp.StageName.equals('Closed Won')) {
                Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
                renewedOpp.Renewal_Status__c = 'Renewed';
                oppsToUpdate.add(renewedOpp);
            }
            else if(renewalOpp.Renewed_Opportunity__c != null && !renewalOpp.IsClosed) {
                Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
                renewedOpp.Renewal_Status__c = 'In Negotiations';
                oppsToUpdate.add(renewedOpp);
            }
            else if(renewalOpp.Renewed_Opportunity__c != null && (renewalOpp.StageName.equals('Closed Lost') || renewalOpp.StageName.equals('Closed Stalled'))) {
                Opportunity renewedOpp = opportunityMap.get(renewalOpp.Renewed_Opportunity__c);
                renewedOpp.Renewal_Status__c = 'Did Not Renew';
                oppsToUpdate.add(renewedOpp);
            }
           
        }
   
    update oppsToUpdate;
        
     }
   
}



Let me know if you need any other info from me!

Thanks,
Greg
Best Answer chosen by ChickenOrBeef
ChickenOrBeefChickenOrBeef
Hey Dom,

I fixed this a while ago (due to some help from Jeff May). I had to change my recursion check class to this:

public class checkRecursive{
    
    private static boolean runBeforeInsert = true;
    private static boolean runBeforeUpdate = true;
    private static boolean runAfterInsert = true;
    private static boolean runAfterUpdate = true;
    private static boolean runAfterDelete = true;
    
    public static boolean runBeforeInsertOnce(){
        
    if(runBeforeInsert){
     runBeforeInsert = false;
     return true;   
    }
    else{
        return runBeforeInsert;
    }
        
    }
    
    public static boolean runBeforeUpdateOnce(){
        
    if(runBeforeUpdate){
     runBeforeUpdate = false;
     return true;   
    }
    else{
        return runBeforeUpdate;
    }
        
    }
    
    public static boolean runAfterInsertOnce(){
        
    if(runAfterInsert){
     runAfterInsert = false;
     return true;   
    }
    else{
        return runAfterInsert;
    }
        
    }
    
    public static boolean runAfterUpdateOnce(){
        
    if(runAfterUpdate){
     runAfterUpdate = false;
     return true;   
    }
    else{
        return runAfterUpdate;
    }
        
    }
    
    public static boolean runAfterDeleteOnce(){
        
    if(runAfterDelete){
     runAfterDelete = false;
     return true;   
    }
    else{
        return runAfterDelete;
    }
        
    }
    
}

That allowed everything to run once.

All Answers

Ashish_SFDCAshish_SFDC
Hi Greg, 


Looks like this has been addressed in your other post, 

https://developer.salesforce.com/forums/ForumsMain?id=906F00000009mMGIAY


See the documentation in the below links, 

Controlling Recursive Triggers

http://developer.force.com/cookbook/recipe/controlling-recursive-triggers

How to avoid infinite recursion in triggers ?

https://success.salesforce.com/answers?id=90630000000hUG8AAM


Regards,
Ashish
Dominic Blythe 18Dominic Blythe 18
Hi Greg, what do you mean by "it doesn't work" ? Do you mean the code in the "after" trigger doesn't ever run?
If you're using the runOnce anywhere else (in the Before trigger for instance, or in a trigger on another object that's being called) then it will set the flag to stop the After trigger running.
ChickenOrBeefChickenOrBeef
Hey Dom,

I fixed this a while ago (due to some help from Jeff May). I had to change my recursion check class to this:

public class checkRecursive{
    
    private static boolean runBeforeInsert = true;
    private static boolean runBeforeUpdate = true;
    private static boolean runAfterInsert = true;
    private static boolean runAfterUpdate = true;
    private static boolean runAfterDelete = true;
    
    public static boolean runBeforeInsertOnce(){
        
    if(runBeforeInsert){
     runBeforeInsert = false;
     return true;   
    }
    else{
        return runBeforeInsert;
    }
        
    }
    
    public static boolean runBeforeUpdateOnce(){
        
    if(runBeforeUpdate){
     runBeforeUpdate = false;
     return true;   
    }
    else{
        return runBeforeUpdate;
    }
        
    }
    
    public static boolean runAfterInsertOnce(){
        
    if(runAfterInsert){
     runAfterInsert = false;
     return true;   
    }
    else{
        return runAfterInsert;
    }
        
    }
    
    public static boolean runAfterUpdateOnce(){
        
    if(runAfterUpdate){
     runAfterUpdate = false;
     return true;   
    }
    else{
        return runAfterUpdate;
    }
        
    }
    
    public static boolean runAfterDeleteOnce(){
        
    if(runAfterDelete){
     runAfterDelete = false;
     return true;   
    }
    else{
        return runAfterDelete;
    }
        
    }
    
}

That allowed everything to run once.
This was selected as the best answer