4

We have a trigger on Opportunity that updates the OpportunityLineItem when the Opportunity is won. We also have workflow rules on the OpportunityLineItem that fire and this causes some recursion to occur.

At the moment this doesn't cause any real problems but while looking at one of the approaches (static boolean class in combination with the trigger setting it once it's fired) - this works fine within the UI but we found the test methods no longer passed. It looks as though the triggers have already fired and the boolean has already been set to prevent further running.

The testmethod is too large to share on SFSE but basically inserts a number of Opportunities then updates the Stage so they are won. Without the CheckRecursive class they assert as expected with CheckRecursive the asserts fail as the triggers have not fired.

Is this a limitation of testmethods or something else I am missing?

Not sure if relevant but I am using test.StartTest() and test.StopTest() either side of the stage update in my test method:

Test.startTest();
update closeOptyList;
Test.stopTest();

Example Trigger:

trigger OptyDemo on Opportunity (before insert, before update)
{
    if(CheckRecursive.RunMe)
    {
        Opty_Utils.someMethod(Trigger.New);
        CheckRecursive.RunMe=false; //Prevent recursion
    }

}

Example Recursive class:

public class CheckRecursive
{
    public static boolean runME = true; //General use
}

1 Answer 1

5

this is a great question. We had similar issues for years. First of all the Recursive class is a great way to make sure that a trigger is executed once.

In your case the complexity has been increased by adding a workflow update. As described in the salesforce documentation "Triggers and Order of Execution" Workflow-Field-Updates can fire triggers again.

  1. If the record was updated with workflow field updates, fires before update triggers and after update triggers one more time (and only one more time), in addition to standard validations. Custom validation rules are not run again.

It's kind of important that the trigger will be executed only one more time.

In your case there is only one solution to make sure that a trigger is executed once: Remove all workflow updates and add the functionality to the existing trigger.

And btw. the usage of a Recursive class doesn't work as intended if you try to update more than 200 records at the same time. Salesforce will split the request in chunks of 200 records.

This behavior is indirectly documented:

Version 20.0 or earlier, if an API call causes a trigger to fire, the chunk of 200 records to process is further split into chunks of 100 records. Note that static variable values are reset between API batches, but governor limits are not. Do not use static variables to track state information between API batches.

However, in case of more than 200 records the trigger will be executed multiple times. (Once for each chunk of data.) However, the runMe variable will be reseted for each API batch, but the execution context stays the same, therefore it is still possible that you reach the api limits.

3
  • Mmmm there's a few workflow rules to investigate then! Regarding your last sentence what's the impact? Is the boolean already set for the second batch of 200?
    – Girbot
    Commented Dec 2, 2014 at 10:00
  • @Girbot added a section about the api batch issue.. Commented Dec 2, 2014 at 10:18
  • Thank you for adding the Batch Issue. That is a very painful thing to run into if you never know about it. Apparently, it considers the Batch API call one transaction and doesn't reset your static variable. How I got around it was to toggle a Boolean variable carefully in a handler class. I have yet to find a better solution to those; especially when it comes to update triggers firing on more conditional workflows. Commented Dec 2, 2014 at 22:29

You must log in to answer this question.

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