SalesforceFoundation / Volunteers-for-Salesforce

Volunteers for Salesforce managed package
BSD 3-Clause "New" or "Revised" License
91 stars 93 forks source link

Mass Email Volunteers May Encounter CPU Timeouts When Activities are Logged #509

Open jesslopez-sf opened 3 years ago

jesslopez-sf commented 3 years ago

The Mass Email Volunteers feature may encounter CPU Timeouts when there are a large number of Volunteers selected, especially if there is programmatic or declarative automation built on the Task object.  While we are inserting a List of Messaging.SingleEmailMessage, Activities (Tasks) inserted for each email are being inserted singly, which will call automations in a non-bulkified manner. There is an Idea on the Trailblazer Community to Bulkify Sent Email Task Creation After Apex Email Send.

Root Cause

Within our VOL_CTRL_SendBulkEmail class (the controller for the SendBulkEmail Visualforce page), we use a List of Messaging.SingleEmailMessage and add Contact email information for each record in the list of Contacts in our case. We then call setSaveAsActivity() and pass it a value of true or false depending upon whether or not the customer has chosen to save emails as Activities (the default option on the page). Once we've iterated over the list, we call Messaging.sendMail(). Unfortunately, the Task (Activity) insertion is done singly, which is why Triggers or other automations are firing every single time. (This is the main code block where the emails get set up and are then sent: https://github.com/SalesforceFoundation/Volunteers-for-Salesforce/blob/master/src/classes/VOL_CTRL_SendBulkEmail.cls#L334-L370).

Salesforce does have a MassEmailMessage class, which seems to be more performant. However, it is limited in what you can set as a whatId on an Activity (only Contract, Case, Opportunity, or Product). Our Volunteers for Salesforce email Activities are being associated with whatIds tied to our custom objects which is likely why this was never an option.

Workarounds:

Steps to Repeat:

  1. Scratch orgs are limited in their number of email sends per day. So, you may need to spin up a dev org.
  2. Create a Campaign, Contacts, and Volunteer Jobs for those Contacts (Snowfakery file attached to Work Item which will automate this for you).
  3. Go to the Campaign and click the Action to Mass Email Volunteers.
  4. In the Email volunteers with Status picklist, select “Confirmed” (assuming you’re using my Snowfakery file).
  5. Check the option to Include Contacts only once.
  6. Check the option to Log an Activity for each email sent.
  7. Select an Email Template.
  8. Click Send.
  9. This will give you a baseline test.
  10. To verify that automations are firing on the Task option in a non-bulkified manner, create a super simple Trigger. Sample below:

    trigger JLTaskTrigger on Task (before insert, before update, before delete, after insert, after update, after delete, after undelete) {
    
    System.debug('*** in jltasktrigger; action is: ' + Trigger.operationType);
    }
  11. Use the Mass Email Volunteers page to send another set of emails. Review your debug log and you’ll see that the Trigger is called for every single Task created.
jesslopez-sf commented 3 years ago

W-9036907