+ Start a Discussion
Darrell GallegosDarrell Gallegos 

Trigger resulting in System.LimitException: Apex CPU time limit exceeded

Hello all.

I am running into the following error: System.LimitException: Apex CPU time limit exceeded.

The error file available in dataloader.io states the following: ERROR: The record couldn’t be saved because it failed to trigger a flow. A flow trigger failed to execute the flow with version ID 3014A000000Xp6z. Flow error messages: This interview has been terminated as another interview in the same bulk execution request failed with the following error: <b>An unhandled fault has occurred in this flow</b><br>An unhandled fault has occurred while processing the flow. 

The email from Salesforce subject: Error Occurred During Flow "Company_Owner_Sync": The flow tried to update these records:... After all the records update failures the message continues This error occurred: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY: UKCheck: System.LimitException: Apex CPU time limit exceeded. For details, see API Exceptions.---The flow tried to update these records: null.

The Process Builder referrenced "Company Owner Sync" attempts to update the owner of related children custom objects (Domain__c, Meridian_Username__c) and Standard Contacts if the Company(Account) owner is changed. 

The UKCheck trigger I have created uses a custom setting to evaluate the Country picklist and stamp a UK Team checkbox if the picklist contains one of the countries specified in the Custom setting. I have included the trigger below. 

Now the trigger works on single UI insert and updates. The Trigger has worked on bulk upload; however, 40 records attempted to be updated are causing the error described above. I have looked in the debub log but it is rather daunting as I am not completely sure what to look for. Hopefully someone can provide assistance based on this description and trigger. Thank you.
trigger UKCheck on Domain__c (before insert, before update) {
    
    Map<String,Country_Codes__c> getCodes = Country_Codes__c.getAll();
        
    for (Domain__c dom : Trigger.new) {
        	
        if(!String.isBlank(dom.Country__c)) {
           for(String s : getCodes.keySet()) {
               if(s.containsIgnoreCase(dom.Country__c)) {
                        
                  dom.UK_Team__c = TRUE;
                        
               }
           } 
        }
    }
}

 
Best Answer chosen by Darrell Gallegos
Waqar Hussain SFWaqar Hussain SF
trigger UKCheck on Domain__c (before insert, before update) {
    Map<String,Country_Codes__c> getCodes = Country_Codes__c.getAll();
    
	if(trigger.isInsert){
		for (Domain__c dom : Trigger.new) {
			if(dom.Country__c != null && getCodes.containsKey(dom.Country__c))
			{
			  dom.UK_Team__c = TRUE;
			}
		}
	}
	
	if(trigger.isUpdate){
		for (Domain__c dom : Trigger.new) {
			if(dom.Country__c != trigger.oldMap.get(dom.Id).Country__c && dom.Country__c != null && getCodes.containsKey(dom.Country__c))
			{
			  dom.UK_Team__c = TRUE;
			}
		}
	}
}

use above code, on update your trigger should only work if the coutry is changed.

All Answers

Amit Chaudhary 8Amit Chaudhary 8
Try to remove nested for loop and update your code like below
trigger UKCheck on Domain__c (before insert, before update) {
    Map<String,Country_Codes__c> getCodes = Country_Codes__c.getAll();
    for (Domain__c dom : Trigger.new) {
		if(dom.Country__c != null && getCodes.containsKey(dom.Country__c))
		{
		  dom.UK_Team__c = TRUE;
		}
    }
}

 
Waqar Hussain SFWaqar Hussain SF
trigger UKCheck on Domain__c (before insert, before update) {
    Map<String,Country_Codes__c> getCodes = Country_Codes__c.getAll();
    
	if(trigger.isInsert){
		for (Domain__c dom : Trigger.new) {
			if(dom.Country__c != null && getCodes.containsKey(dom.Country__c))
			{
			  dom.UK_Team__c = TRUE;
			}
		}
	}
	
	if(trigger.isUpdate){
		for (Domain__c dom : Trigger.new) {
			if(dom.Country__c != trigger.oldMap.get(dom.Id).Country__c && dom.Country__c != null && getCodes.containsKey(dom.Country__c))
			{
			  dom.UK_Team__c = TRUE;
			}
		}
	}
}

use above code, on update your trigger should only work if the coutry is changed.
This was selected as the best answer
Darrell GallegosDarrell Gallegos
Amit and Waqar thank you both. These are both great ideas and I should have thought about these. I'm learning and this is part of of the learning process. Thankfully, individuals is Salesforce communities are so helpful.

I am going to incorporate these tweeks and come back to this thread. I will have to write a test class before I can fully test this. My question regarding the test class for this check for country code change is as follows. To properly test this line of code I would create a record with a country code not listed in my custom setting and update the record to a Country__c listed in the setting. Also I would  create another record making a change but NOT update the Country__c. Is this correct? 
Waqar Hussain SFWaqar Hussain SF
Yes Darell, You are on the right path. 
Amit Chaudhary 8Amit Chaudhary 8
Hi Darrell,

I will recommend you to remove extra for loop from code. Due to multiple for loop we used to get Apex CPU time limit exceeded error
Try to update your code like below
 
trigger UKCheck on Domain__c (before insert, before update) 
{
    Map<String,Country_Codes__c> getCodes = Country_Codes__c.getAll();
		for (Domain__c dom : Trigger.new) {

			if( trigger.isInsert && dom.Country__c != null && getCodes.containsKey(dom.Country__c))
			{
			  dom.UK_Team__c = TRUE;
			}
			else if ( trigger.isUpdate && dom.Country__c != null && dom.Country__c != trigger.oldMap.get(dom.Id).Country__c &&  getCodes.containsKey(dom.Country__c) )
			{
			  dom.UK_Team__c = TRUE;
			}
		}
	}
}
Please check below post for Trigger best practice http://amitsalesforce.blogspot.com/2015/06/trigger-best-practices-sample-trigger.html

For test class try like below
@isTest 
public class UKCheckTest 
{
	static testMethod void testMethod1() 
	{
		Country_Codes__c cc = new Country_Codes__c();
			cc.name ='USA';
			// insert all required field
		insert cc;
		
		Domain__c dom = new Domain__c();
		dom.Country__c ='USA';
		// insert all required field here
        insert dom;		
		
	}
}

Let us know if this will help you
 
Darrell GallegosDarrell Gallegos
This is my current Test Class. I have some modifications to make to incorporate the new line. Thank you for pointing me in the right direction. I cannot get enough of learning APEX!!!
 
@isTest
public class UKCheck_Test {
    
    @TestSetup 
    static void createUser() {
        
        UserRole r = new UserRole(DeveloperName = 'SovrnCustomRole', Name = 'Sovrn Role');
        insert r;
        
        User u1 = new User();
        u1.LastName          = 'Test1';
        u1.Alias             = 'alias1';
        u1.Email             = 'test1@fake.com';
        u1.Username          = 'testsovrn2018@fake.com';
        u1.CompanyName       = 'Test1';
        u1.TimeZoneSidKey    ='America/Los_Angeles';
        u1.EmailEncodingKey  ='UTF-8';
        u1.LocaleSidKey      = 'en_US';
        u1.UserRoleId        = r.Id;
        u1.LanguageLocaleKey = 'en_US';
        u1.ProfileId         = [SELECT Id FROM Profile WHERE Name = 'Publisher Advocate'].Id;
        insert u1;
        
    }

    static testmethod void validateUKCheck () {
        
        List<Account> accts = new List<Account>();
        List<Domain__c> domList = new List<Domain__c>();
        
        //Create Companies(Account)        
        Account acct   = new Account();
        acct.Name      = 'TestCompany1';
        acct.OwnerId   = UserInfo.getUserId();
        accts.add(acct);
        System.debug('Acct equals ' + acct.Name);
        System.debug('Acct Owner is ' + acct.OwnerId);
        
        Account acct1 = new Account();
        acct1.Name    = 'TestCompany2';
        acct1.OwnerId = [SELECT Id FROM User WHERE UserName = 'testsovrn2018@fake.com'].Id;
        accts.add(acct1);
        System.debug('Acct1 equals ' + acct1.Name);
        System.debug('Acct1 Owner is ' + acct1.OwnerId);
        
        Test.startTest();
        insert accts;
        Test.stopTest();
        
        //Create Custom Setting
        Country_Codes__c cS = new Country_Codes__c();
        cS.Name             = 'GB';
        cS.Country__c       = 'GB';
        insert cS;
        
        //Create Domain records
        Domain__c UKDom  = new Domain__c();
        UKDom.Name       = 'testdomain.com';
        UKDom.Website__c = 'www.testdomain.com';
        UKDom.Country__c = 'GB';
        UKDom.Uk_Team__c = TRUE;
        UKDom.Company__c = acct.Id;
        UKDom.OwnerId    = UserInfo.getUserId();
        System.debug('UKDom domain Company__c is ' + acct.Name);
        System.debug('UKDom domain ownerID is ' + UKDom.OwnerId);        
        
        domList.add(UKDom);
        
        Domain__c noUK  = new Domain__c();
        noUK.Name       = 'testdomainnoUK.com';
        noUK.Website__c = 'www.testdomainnoUK.com';
        noUK.Country__c = 'US';
        noUK.OwnerId    = acct1.OwnerId;
        noUk.Company__c = acct1.Id;
        noUK.UK_Team__c = FALSE;
        System.debug('noUK domain Company__c is ' + acct1.Name);
        System.debug('noUK domain Company__c is ' + acct1.Id);
        System.debug('noUK domain ownerID is ' + noUK.OwnerId);
        
        domList.add(noUK);
        
		insert domList;
        System.debug('noUK domain ID ' + noUk.Id);
        
        Domain__c domainToUpdate = [SELECT Id, Name, Company__c, Company__r.OwnerId, OwnerId FROM Domain__c WHERE Id = :noUK.Id];
        domainToUpdate.Company__c = acct.Id;
        domainToUpdate.OwnerId = acct.OwnerId;
        update domainToUpdate;
        
        System.debug(domainToUpdate);
        System.debug('NOW noUK domain Company__c is ' + domainToUpdate.Company__c);
        System.debug('NOW noUK domain ownerID is ' + domainToUpdate.OwnerId);


        System.assertEquals(UKDom.UK_Team__c, True);
        System.assertEquals(noUK.UK_Team__c, FALSE);
        System.assertEquals(domainToUpdate.OwnerId, acct.OwnerId);

    	}
    
}

 
Darrell GallegosDarrell Gallegos
Thanks Amit - I still have to add the new additions to my trigger. I just walked into work so I will begin this now. I will let you know.
Darrell GallegosDarrell Gallegos
Amit - the existing test class I supplied above gets me 94% coverage with 16/17 lines covered. 

What am I missing here to get 100%?User-added image
Amit Chaudhary 8Amit Chaudhary 8
You need to perform the update in you test class like below
@isTest
public class UKCheck_Test {
    
    @TestSetup 
    static void createUser() {
        
        UserRole r = new UserRole(DeveloperName = 'SovrnCustomRole', Name = 'Sovrn Role');
        insert r;
        
        User u1 = new User();
        u1.LastName          = 'Test1';
        u1.Alias             = 'alias1';
        u1.Email             = 'test1@fake.com';
        u1.Username          = 'testsovrn2018@fake.com';
        u1.CompanyName       = 'Test1';
        u1.TimeZoneSidKey    ='America/Los_Angeles';
        u1.EmailEncodingKey  ='UTF-8';
        u1.LocaleSidKey      = 'en_US';
        u1.UserRoleId        = r.Id;
        u1.LanguageLocaleKey = 'en_US';
        u1.ProfileId         = [SELECT Id FROM Profile WHERE Name = 'Publisher Advocate'].Id;
        insert u1;
        
    }

    static testmethod void validateUKCheck () {
        
        List<Account> accts = new List<Account>();
        List<Domain__c> domList = new List<Domain__c>();
        
        //Create Companies(Account)        
        Account acct   = new Account();
        acct.Name      = 'TestCompany1';
        acct.OwnerId   = UserInfo.getUserId();
        accts.add(acct);
        System.debug('Acct equals ' + acct.Name);
        System.debug('Acct Owner is ' + acct.OwnerId);
        
        Account acct1 = new Account();
        acct1.Name    = 'TestCompany2';
        acct1.OwnerId = [SELECT Id FROM User WHERE UserName = 'testsovrn2018@fake.com'].Id;
        accts.add(acct1);
        System.debug('Acct1 equals ' + acct1.Name);
        System.debug('Acct1 Owner is ' + acct1.OwnerId);
        
        Test.startTest();
        insert accts;
        Test.stopTest();
        
        //Create Custom Setting
        Country_Codes__c cS = new Country_Codes__c();
        cS.Name             = 'GB';
        cS.Country__c       = 'GB';
        insert cS;
        
        //Create Custom Setting
        Country_Codes__c cS1 = new Country_Codes__c();
        cS1.Name             = 'USA';
        cS1.Country__c       = 'USA';
        insert cS1;

        //Create Domain records
        Domain__c UKDom  = new Domain__c();
        UKDom.Name       = 'testdomain.com';
        UKDom.Website__c = 'www.testdomain.com';
        UKDom.Country__c = 'GB';
        UKDom.Uk_Team__c = TRUE;
        UKDom.Company__c = acct.Id;
        UKDom.OwnerId    = UserInfo.getUserId();
        System.debug('UKDom domain Company__c is ' + acct.Name);
        System.debug('UKDom domain ownerID is ' + UKDom.OwnerId);        
        
        domList.add(UKDom);
        
        Domain__c noUK  = new Domain__c();
        noUK.Name       = 'testdomainnoUK.com';
        noUK.Website__c = 'www.testdomainnoUK.com';
        noUK.Country__c = 'US';
        noUK.OwnerId    = acct1.OwnerId;
        noUk.Company__c = acct1.Id;
        noUK.UK_Team__c = FALSE;
        System.debug('noUK domain Company__c is ' + acct1.Name);
        System.debug('noUK domain Company__c is ' + acct1.Id);
        System.debug('noUK domain ownerID is ' + noUK.OwnerId);
        
        domList.add(noUK);
        
		insert domList;
        System.debug('noUK domain ID ' + noUk.Id);
        
        Domain__c domainToUpdate = [SELECT Id, Name, Company__c, Company__r.OwnerId, OwnerId FROM Domain__c WHERE Id = :noUK.Id];
        domainToUpdate.Company__c = acct.Id;
        domainToUpdate.OwnerId = acct.OwnerId;
        update domainToUpdate;
        
        System.debug(domainToUpdate);
        System.debug('NOW noUK domain Company__c is ' + domainToUpdate.Company__c);
        System.debug('NOW noUK domain ownerID is ' + domainToUpdate.OwnerId);


        System.assertEquals(UKDom.UK_Team__c, True);
        System.assertEquals(noUK.UK_Team__c, FALSE);
        System.assertEquals(domainToUpdate.OwnerId, acct.OwnerId);

		UKDom.Country__c ='USA';
		update UKDom;
			
    	}
    
}

If possible try to mearge both insert and update in trigger like trigger which i posted above
 
Darrell GallegosDarrell Gallegos
Amit that was a homerun!!!!
Darrell GallegosDarrell Gallegos
Amit is there a benefit to using the else if? Is this a more efficient use of code execution? It does cut down lines of code for sure, but I am wondering if this code is better or conforms to best practices?
Amit Chaudhary 8Amit Chaudhary 8
Please post your final code i will update that for you