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
steve nabors 7steve nabors 7 

Exiting a Trigger for operations involving mass updates

We have a nightly queueable job that runs on the Contact object that does ranking.  All the process does is update 1 field, possibly on up to 12,000 contacts.  No extra processing needs to occur since this field isn't used for anything else (read-only, info only).  We are running into CPU limits because of all the normal processing in the Trigger.  I have decided to exit the trigger if it detects if that field has changed (the batch job is the only thing that can change it).  I've got this working and wanted to know if the below was the best way to do this:

trigger MasterContactTrigger on Contact (
    before insert, after insert, 
    before update, after update) {

   if (Trigger.isUpdate) {
      for(Contact cont : Trigger.new) {
         Contact oldContact = Trigger.oldMap.get(cont.Id);
         if (cont.field__c != oldContact.field__c) return;
      }
   }

...........
Best Answer chosen by steve nabors 7
PradeepgorePradeepgore
Hi Steve,

Firstly, appreciate that you moved to queuebale

Please use logic less trigger and let trigger handler/helper contain all processing

You can use the custom setting in which there is mention of recordcount and compare that with the trigger size

E.g.  
//Set limitTriggerProcessingCount say 100/200 depending on ask
if(objContactSetting.limitTriggerProcessingCount >= Trigger.size() )
{
        //Exceute the logic henceforth by calling the class that is common for both 
        // queuebale hanlder and trigger handler
}
else {
//do nothing
//Let nightly queueable handle this
}

//By this approach, there is no wait for the nightly job for few records

The common class method for both trigger and queuebale can check System.isQueueable() to differentiate the execution.

More details linked here:

https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_system.htm#apex_System_system_isQueueable

Needless to say marking this as best answer will guide future visitors.

Additionally I can be contacted at pradeepgore60@gmail.com

-Pradeep Gore 
 

All Answers

PradeepgorePradeepgore
Hi Steve,

Firstly, appreciate that you moved to queuebale

Please use logic less trigger and let trigger handler/helper contain all processing

You can use the custom setting in which there is mention of recordcount and compare that with the trigger size

E.g.  
//Set limitTriggerProcessingCount say 100/200 depending on ask
if(objContactSetting.limitTriggerProcessingCount >= Trigger.size() )
{
        //Exceute the logic henceforth by calling the class that is common for both 
        // queuebale hanlder and trigger handler
}
else {
//do nothing
//Let nightly queueable handle this
}

//By this approach, there is no wait for the nightly job for few records

The common class method for both trigger and queuebale can check System.isQueueable() to differentiate the execution.

More details linked here:

https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_system.htm#apex_System_system_isQueueable

Needless to say marking this as best answer will guide future visitors.

Additionally I can be contacted at pradeepgore60@gmail.com

-Pradeep Gore 
 
This was selected as the best answer
steve nabors 7steve nabors 7
Thanks for your response.  I went ahead and used your suggestion and updated the Apex Code to the following:
 
trigger MasterContactTrigger on Contact (
    before insert, after insert, 
    before update, after update) {
		
        // do not process trigger if invoked by queueable Apex Job
        If (System.isQueueable()) return;
                
        if (Trigger.isBefore && Trigger.isUpdate) {

.............

2nd Part of my question which I wasn't specific on,  Should this be in a For..Loop or can it just be listed the way I have it above?  I'm still a little confused at what happens when bulkafying a trigger.  What if during the batch job update, someone does a manual update in the UI, would it be "bulk'd" in with the batch class and possibly exit the trigger because of the condition above, or would the system separate those out?
PradeepgorePradeepgore
Hi Steve, 

Have divided the questions herein

Q1. Should this be in a For..Loop or can it just be listed the way I have it above?  
you may use that in for loop such as below. This will differentiate if the field is changed and the change is because of queueable/batch class

for(Contact cont : Trigger.new) {
         Contact oldContact = Trigger.oldMap.get(cont.Id);
         
         if(!System.isQueueable() || !System.isBatch){ // verify the change is not because of queueable/batch class
                ...
                ...
         }
         
      }
 
 Also, please shift the trigger logic in handler class if possible. SHOULD THIS ADDS MORE TO YOUR CONFUSION SKIP IT
 
 trigger MasterContactTrigger on Contact (
    before insert, after insert, 
    before update, after update) {
        MasterContactTriggerHandler.MethodName(Trigger.NewMap,Trigger.oldMap);//where MasterContactTriggerHandler is new class  
    
    }
    public class MasterContactTriggerHandler{
        public static void MethodName(Map<Id,Contact> newContactMap,Map<Id,Contact> oldContactMap){
            if(!newContactMap.isEmpty()){
                ....
            }
            if(!oldContactMap.isEmpty()){
            
            }
        }
    }

Q2. What if during the batch job update, someone does a manual update in the UI
Rarest as you said it is nightly queueable job and it is the only thing that can change it


Q3 would it be "bulk'd" in with the batch class and possibly exit the trigger because of the condition above, 
Would not able to coment , until I see the whole trigger and batch.


Q4 . would the system separate those out? - yes 

Hope this helps.
Pradeep Gore