You need to sign in to do that
Don't have an account?
ChickenOrBeef
Trigger going over "heap" limit when mass updating
Hello everyone,
I have an After Update trigger on the Task object that creates a custom object record called a "Related Activity" for all the accounts related to the Task's account.
So for example, if an account called Diet Coke has a parent called Coca Cola and two siblings called Coke Zero and Dasani, then the new task under Diet Coke should show up as a Related Activity under Coca Cola, Coke Zero, and Dasani.
Anywho, I'm trying to use this trigger to mass update all our existing completed tasks (over 300,000 tasks) in batches of 200. The problem? Some of the batches seem to be going way over the "heap" limit, which I never knew about until now.
I'm still pretty confused on what will cause a "heap" issue, so can someone be kind enough to let me know which sections of my trigger might be causing the issue, and perhaps how to go about fixing it? Let me know if you need any additional info from me!
Thanks!
-Greg
I have an After Update trigger on the Task object that creates a custom object record called a "Related Activity" for all the accounts related to the Task's account.
So for example, if an account called Diet Coke has a parent called Coca Cola and two siblings called Coke Zero and Dasani, then the new task under Diet Coke should show up as a Related Activity under Coca Cola, Coke Zero, and Dasani.
Anywho, I'm trying to use this trigger to mass update all our existing completed tasks (over 300,000 tasks) in batches of 200. The problem? Some of the batches seem to be going way over the "heap" limit, which I never knew about until now.
I'm still pretty confused on what will cause a "heap" issue, so can someone be kind enough to let me know which sections of my trigger might be causing the issue, and perhaps how to go about fixing it? Let me know if you need any additional info from me!
public class ClassRelatedActivities{ public void addRelatedActivities(List<Task> tasks,Map<ID,Task> oldTasks){ Set<String> accountsInTrigger = new Set<String>(); Set<String> contactsInTrigger = new Set<String>(); Set<String> parentSet = new Set<String>(); Set<String> clientSet = new Set<String>(); Set<String> agencySet = new Set<String>(); Set<String> siblingAccounts = new Set<String>(); Map<String,String> contactMap = new Map<String,String>(); Map<String,String> parentMap = new Map<String,String>(); Map<String,String> siblingParentMap = new Map<String,String>(); Map<String,String> clientAgencyMap = new Map<String,String>(); Map<String,String> agencyClientMap = new Map<String,String>(); List<Related_Activity__c> relatedActivitiesToAdd = new List<Related_Activity__c>(); FOR(Task t : tasks){ IF(t.Mass_Update__c == TRUE && oldTasks.get(t.Id).Mass_Update__c != TRUE){ IF(t.WhatId != NULL && string.valueOf(t.WhatId).startsWith('001')){ accountsInTrigger.add(t.WhatId); } ELSE IF(t.WhatId == NULL && t.WhoId != NULL && string.valueOf(t.WhoId).startsWith('003')){ contactsInTrigger.add(t.WhoId); } } } FOR(Contact c : [SELECT Id,AccountId FROM Contact WHERE Id In :contactsInTrigger]){ contactMap.put(c.Id,c.AccountId); accountsInTrigger.add(c.AccountId); } List<Account> childAccounts = [SELECT Id, ParentId FROM Account WHERE ParentId In :accountsInTrigger]; FOR(Account pa : [SELECT Id,ParentId FROM Account WHERE ParentId != NULL AND Id In :accountsInTrigger]){ parentMap.put(pa.Id,pa.ParentId); parentSet.add(pa.ParentId); } FOR(Account fc : [SELECT Id, ParentId FROM Account WHERE ParentId In :parentSet]){ siblingParentMap.put(fc.Id,fc.ParentId); siblingAccounts.add(fc.Id); } List<Client_Agency_Relationship__c> clientAgencies = [SELECT Id,Client__c,Agency__c FROM Client_Agency_Relationship__c WHERE Client__c In :accountsInTrigger OR Agency__c In :accountsInTrigger]; FOR(Task t0 : tasks){ String accountID0; IF(t0.WhatId != NULL){ accountID0 = t0.WhatId; } ELSE IF(t0.WhatId == NULL && t0.WhoId != NULL){ accountID0 = contactMap.get(t0.WhoId); } FOR(Account a : childAccounts){ IF(a.ParentId == accountID0){ Related_Activity__c ra0 = new Related_Activity__c(); IF(t0.Subject.length() > 80){ ra0.Name = t0.Subject.SubString(0,80); } ELSE{ ra0.Name = t0.Subject; } ra0.Date__c = t0.ActivityDate; ra0.Description__c = t0.Description; ra0.Assigned_To__c = t0.OwnerId; ra0.Activity_ID__c = t0.Id; ra0.Name__c = t0.WhoId; ra0.Relationship__c = 'Parent'; ra0.Account__c = a.Id; ra0.Related_To__c = accountID0; relatedActivitiesToAdd.add(ra0); } } } FOR(Task t1 : tasks){ String accountID1; String parentID1; IF(t1.WhatId != NULL){ accountID1 = t1.WhatId; parentID1 = parentMap.get(t1.WhatId); } ELSE IF(t1.WhatId == NULL && t1.WhoId != NULL){ accountID1 = contactMap.get(t1.WhoId); parentID1 = parentMap.get(contactMap.get(t1.WhoId)); } FOR(String a1 : siblingAccounts){ IF(siblingParentMap.get(a1) == parentID1 && a1 != accountID1){ Related_Activity__c ra1 = new Related_Activity__c(); IF(t1.Subject.length() > 80){ ra1.Name = t1.Subject.SubString(0,80); } ELSE{ ra1.Name = t1.Subject; } ra1.Date__c = t1.ActivityDate; ra1.Description__c = t1.Description; ra1.Assigned_To__c = t1.OwnerId; ra1.Activity_ID__c = t1.Id; ra1.Name__c = t1.WhoId; ra1.Relationship__c = 'Sibling'; ra1.Account__c = a1; ra1.Related_To__c = accountID1; relatedActivitiesToAdd.add(ra1); } } } FOR(Task t2 : tasks){ String accountID2; IF(t2.WhatId != NULL){ accountID2 = t2.WhatId; } ELSE IF(t2.WhatId == NULL && t2.WhoId != NULL){ accountID2 = contactMap.get(t2.WhoId); } FOR(Client_Agency_Relationship__c car0 : clientAgencies){ IF(car0.Agency__c == accountID2){ Related_Activity__c ra2 = new Related_Activity__c(); IF(t2.Subject.length() > 80){ ra2.Name = t2.Subject.SubString(0,80); } ELSE{ ra2.Name = t2.Subject; } ra2.Date__c = t2.ActivityDate; ra2.Description__c = t2.Description; ra2.Assigned_To__c = t2.OwnerId; ra2.Activity_ID__c = t2.Id; ra2.Name__c = t2.WhoId; ra2.Relationship__c = 'Agency'; ra2.Account__c = car0.Client__c; ra2.Related_To__c = accountID2; relatedActivitiesToAdd.add(ra2); } } } FOR(Task t3 : tasks){ String accountID3; IF(t3.WhatId != NULL){ accountID3 = t3.WhatId; } ELSE IF(t3.WhatId == NULL && t3.WhoId != NULL){ accountID3 = contactMap.get(t3.WhoId); } FOR(Client_Agency_Relationship__c car1 : clientAgencies){ IF(car1.Client__c == accountID3){ Related_Activity__c ra3 = new Related_Activity__c(); IF(t3.Subject.length() > 80){ ra3.Name = t3.Subject.SubString(0,80); } ELSE{ ra3.Name = t3.Subject; } ra3.Date__c = t3.ActivityDate; ra3.Description__c = t3.Description; ra3.Assigned_To__c = t3.OwnerId; ra3.Activity_ID__c = t3.Id; ra3.Name__c = t3.WhoId; ra3.Relationship__c = 'Client'; ra3.Account__c = car1.Agency__c; ra3.Related_To__c = accountID3; relatedActivitiesToAdd.add(ra3); } } } FOR(Task t4 : tasks){ String accountID4; String parentID4; IF(t4.WhatId != NULL){ accountID4 = t4.WhatId; parentID4 = parentMap.get(t4.WhatId); } ELSE IF(t4.WhatId == NULL && t4.WhoId != NULL){ accountID4 = contactMap.get(t4.WhoId); parentID4 = parentMap.get(contactMap.get(t4.WhoId)); } FOR(String a4 : parentSet){ IF(parentID4 == a4){ Related_Activity__c ra4 = new Related_Activity__c(); IF(t4.Subject.length() > 80){ ra4.Name = t4.Subject.SubString(0,80); } ELSE{ ra4.Name = t4.Subject; } ra4.Date__c = t4.ActivityDate; ra4.Description__c = t4.Description; ra4.Assigned_To__c = t4.OwnerId; ra4.Activity_ID__c = t4.Id; ra4.Name__c = t4.WhoId; ra4.Relationship__c = 'Child'; ra4.Account__c = a4; ra4.Related_To__c = accountID4; relatedActivitiesToAdd.add(ra4); } } } IF(relatedActivitiesToAdd.size() > 0){ INSERT relatedActivitiesToAdd; } } }
Thanks!
-Greg
Just to update on this, the reason my heap was going crazy was because I didn't take into account that a Contact may not be attached to an Account. Once I made that quick change (I made sure the Contacts in the trigger had AccountID populated), the heap went down dramatically.
Thanks for your help!
-Greg
All Answers
Heap is just the amount of memory that the execution is using. All the variables you have, the lists and maps you copy queries into and the list of related activities you generate are contributing to the heap.
Your code doesn't look particularly wasteful to me. And if it's doing what you need it to do, maybe you could just reduce your batch size.
I may have to end up just doing a smaller batch size, but I want to see if optimization can solve this issue before I throw in the towel.
I tried putting debug statements that show both the heap size and CPU time (which is also an error I'm receiving for some batches). But when mass updating 100 records (a smaller batch size, to make sure it works) only the last six debug statements show up. Any idea why?
Here's the code with the 24 debug statements:
And here are the debug results:
Any idea why those first 18 debug statements wouldn't run? The trigger works fine and none of the statements are within loops.
Thanks!
-Greg
I tried looking at the Debug Log in the Salesforce UI, but only the same Debug Statements show up.
Just to update on this, the reason my heap was going crazy was because I didn't take into account that a Contact may not be attached to an Account. Once I made that quick change (I made sure the Contacts in the trigger had AccountID populated), the heap went down dramatically.
Thanks for your help!
-Greg