3
  1. Update 405 records on an object (So it executes the trigger 3 times 200+200+3 i.e, each batch holds 200 records)
  2. There is a process builder which in turn is updating the same object (Will fire the trigger again)
  3. Workflow field update - will fire the trigger again)

So in this example, trigger will run 6*3 times (i.e., per batch it will execute 6 times - 3 before and 3 after) but we need the trigger to execute only 2 times (1 before and 1 after)

i.e., triggers should not execute when process builder or work flow field update updates the record

Recursive Static Variable: Will work only for first 200 records

2
  • Can you explain more in details what are you trying to achieve, what have you tried (probably with an example) and what does not work. It is hard to understand that based on your question right now.
    – kurunve
    Commented Jul 6, 2018 at 12:37
  • 2
    While the wording is a bit clumsy, I think it's relatively clear that OP is asking for how to implement a recursion/mutli-run prevention mechanism. David's answer is spot on, so I'm voting to leave this one open.
    – Derek F
    Commented Jul 6, 2018 at 15:15

2 Answers 2

6

This is a great example of why so-called recursion protection like this:

public class MyTriggerHandler {
    static Boolean hasAlreadyRun = false;
}

trigger MyTrigger on MyObject__c (after update) {
    if (!MyTriggerHandler.hasAlreadyRun) {
        // Do stuff
        MyTriggerHandler.hasAlreadyRun = true;
    }
}

is a terrible pattern.

Without seeing more of your code, you probably have two options.

The first is to fix the recursion. Fold your Process Builder and your Workflow Rule into the code of your trigger handler. Honestly, I would do this anyway - if you're doing bulk loads on this data you don't need to have extra trigger invocations taking up transaction time anyway.

The second is to use a static collection-based recursion guard, something like this:

public class MyTriggerHandler {
    static Set<Id> recordsAlreadyProcessed = new Set<Id>();

    public static void afterUpdate(List<MyObject__c> newList, Map<Id, MyObject__c> oldMap) {
        List<MyObject__c> toProcess = new List<MyObject__c>();

        for (MyObject__c m : newList) {
            if (!recordsAlreadyProcessed.contains(m.Id)) {
                recordsAlreadyProcessed.add(m.Id);
                toProcess.add(m);
            }
        }

        // Now process `toProcess` only.
}

trigger MyTrigger on MyObject__c (after update) {
    MyTriggerHandler.afterUpdate(Trigger.new, Trigger.oldMap);
}

Note however that this isn't necessarily a copy-and-paste solution. If your trigger should reprocess records that undergo specific changes from workflow rules, or even depend upon those updates, this pattern will break that. You need to carefully evaluate how your trigger and your declarative automations interact before you add any kind of suppression logic, and be aware that using this pattern does have implications for any future implementations of declarative automation you may do.

2
  • The solution with recordsAlreadyProcessed didn't work in my case. I may only suggest, it's because static variables don't refresh when a batch is being retried. So I'm verifying outcome of operation when filtering records. "For each internal batch, if Salesforce can’t process all the records in a batch in 10 minutes or less, the batch fails. Salesforce will re-try failed batches up to a maximum of 10 retries." developer.salesforce.com/docs/atlas.en-us.api_bulk_v2.meta/… Commented Jul 1, 2019 at 9:04
  • @VladimirRomanov Each batch in a Bulk API job spans potentially a large number of transactions (across up to 10,000 records) - the static lifespan boundary is the transaction.
    – David Reed
    Commented Jul 1, 2019 at 11:25
2

Usually, during bulk data load, it is recommended to deactivate the triggers, process builder's processes, workflow rules, so that bulk data load will not consume much time and you will not end up with unexpected results due to recursion.

There are two options to make Salesforce system to sync with data updates.

  1. You can prepare csv file with those fields which are getting updated by processes and workflow rules

  2. You need to create a separate batch process to update those data considering the logic written in process builder and workflow rules.

You must log in to answer this question.

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