4

I recently encountered a business logic bug in our org that was accidentally deducting a customer 2x for completing an event that only actually occurred once. Using dev console I was able to determine that the method was running twice as a result of a Workflow Field Update that caused the transaction to loop through the order of execution a second time. Unchecking the "re-evaluate" box on the workflow rule didn't stop the bug.

So, I went the route of creating a 'RunOnce' style Boolean in a Helper Class, checking if it is false at the start of the method, and then setting it to true as the last line in the entire method (even after DML updates). This of course doesn't stop the record(s) from going through order of execution again, but it does stop the method from running since it already ran.

Example with main business logic removed for size purposes:

public static void updateUsedTrainingTimeUsingEventMaps(Map<Id,Event> oldEventMap, Map<Id,Event> newEventMap){
    if(ValidatorClass.UpdateTrainingTimeTriggerFired == false){ // check if this method has run already

        for(Event event : newEventMap.values())
        {
            A BUNCH OF BUSINESS LOGIC, FIELD UPDATES, ADDING TO UPDATE LISTS, ETC
        } // end of for loop

    update accountMap.values();
    ValidatorClass.UpdateTrainingTimeTriggerFired = true; // stop method from running again in same transaction

} // end of updateUsedTrainingTimeUsingEventMaps()

Question: Being that this is my first time doing this, I am unsure of how exactly this effects (if at all), mass updates that trigger this method. I learned recently (in SFDev450 class) that Salesforce handles records in sets of 200 in loops - but I am unsure if that means they also only pass 200 records to the method at once.

Does this mean:

  1. Each 200 records get their own transaction per 200, and by extension, a fresh reset of the Boolean?

OR

  1. Will my 201st record not run the method since it's a second set of 200 being run through the method in the same transaction where the Boolean is now true?

OR

  1. Will all of my records (let's say 405) be sent to the method at the same time but just run through the loops in sets of 200 before doing my final DML update outside of the loop, resulting in all 405 running the method once regardless of how many times subsequent order of executions may start in that transaction?

OR

  1. None of the above? (Please specify)

Many thanks for your insight!

1
  • Door number two.
    – Adrian Larson
    Commented Jul 14, 2016 at 16:29

1 Answer 1

3

Very astute question! The answer is number 2. You want to put your boolean in your trigger where the class is called from. You'll need a trigger utility class to hold the boolean. This is a large part of why trigger platforms are so useful, particularly ones that have a "trigger main" that acts as a distribution class that follows the logic of a regular base trigger from which your helper classes are called.

Example of Utility class:

Public class TrggrUtility{

   public static boolean RunOnce = False;

}

Test inside of trigger:

If(!TrggrUtility.RunOnce) 
{
   // do... call method
   TrggrUtility.RunOnce = true;

}else{

  // exit trigger or code section

}
2
  • Thank you! Am I correct in assuming that if I want 2 different methods in a single trigger to each run once then I would either wrap them both in the same if{} or create 2 separate bools? What I mean is, if I have if(!TrggrUtility.RunOnce){ Class.Method1 } and then later I have if(!TrggrUtility.RunOnce){ Class.Method2 } in the same trigger, the second method won't fire because the bool is already true from the first? Commented Jul 14, 2016 at 17:08
  • 1
    That's correct. Unless the flow of logic in your trigger allows your If statement to enclose both of them, then you'd need to have two different public static booleans. That's the beauty of having a Trigger Utility Class like the above, you can add as many of them as you want. If you wanted, you could even create them as a public static list<boolean>RunOnce and then use RunOnce[0], RunOnce[1], etc. (by default, all bools are created as false since technically they can't be null).
    – crmprogdev
    Commented Jul 14, 2016 at 17:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .