Get #Buildspiration with Asynchronous Apex Triggers in Summer ‘19

Get your #buildspiration from the Summer ’19 release! We are sharing five of our favorite release features for Developers (and Admins) as part of the The MOAR You Know learning journey. Get the release highlights as curated and published by our evangelists. Complete the trailmix by July 31, 2019, to get a special community badge, and unlock a contribution of $10 to FIRST.

Saving records on Salesforce causes the platform to start a series of calculations, to help with business logic and database updates. These calculations are also known as an Apex transaction. The Apex transaction can take more time to complete the business logic and consume more resources . You can reduce these transaction times and limit constraints by decoupling resource-intensive, non-transactional logic from database transaction and execute asynchronously. That means, you can first execute the database transaction part that generate an event after completion. Then you can use this event to trigger other asynchronous business processing. This can be achieved with a combination of Change Data Capture and the new exciting enhancement in Summer ’19 release, asynchronous Apex triggers.

What is Change Data Capture and asynchronous Apex trigger?

Change Data Capture publishes the deltas of Salesforce data for new records or changed records. This feature can be enabled for any supported sObject in your org. Once it is enabled, it starts publishing the events whenever we create, update, delete or undelete a record. The published event contains metadata information about the record and also all the changed field values.

/* 
    Sample Change Data Capture event published on update of an Opportunity record
*/
 {
  "schema": "90f--o4WxM9RZZ8PKPgJog",
  "payload": {
    "LastModifiedDate": "2019-05-21T17:54:33.000Z",
    "ExpectedRevenue": 500002,
    "Amount": 5000020,
    "ChangeEventHeader": {
      "commitNumber": 10433619776237,
      "commitUser": "005B0000005lfkFIAQ",
      "sequenceNumber": 1,
      "entityName": "Opportunity",
      "changeType": "UPDATE",
      "changeOrigin": "com/salesforce/api/soap/46.0;client=SfdcInternalAPI/",
      "transactionKey": "0005e058-5808-e754-5fee-196069fcd60a",
      "commitTimestamp": 1558461273000,
      "recordIds": [
        "006B0000004VTRXIA4"
      ]
    }
  }

Asynchronous Apex triggers are change event triggers that run asynchronously after a database transaction is completed. They are ‘after-insert’ triggers and can be defined with the after insert keywords. They can be created the same way you create regular Apex triggers. You set the trigger to use a change event object instead of an sObject. The change event object name is suffixed with ChangeEvent. For example, Account change event object is named AccountChangeEvent. The change event object name for the custom object is suffixed with __ChangeEvent.

How does it work?

When a record is created or updated, Change Data Capture publishes an event and a change event trigger can then process that event asynchronously.

Let’s look at an example transaction. Whenever an opportunity record is created or updated, you need to check whether the corresponding account is qualified to be a high priority customer. This process of qualifying high priority customers is very limit-intensive and computationally slow.

For this scenario, we can enable Change Data Capture for the Opportunity object, then implement the complex business logic in the OpportunityChangeAsyncTrigger (asynchronous Apex trigger).

When the opportunity record is created or changed, the OpportunityChangeAsyncTrigger is automatically fired and executes the complex business logic defined in AccountClassifier. Each change event processed in the trigger contains the changed record fields and metadata information about the change in header fields.


[alt text: Pictorial representation of transactional flow for the example transaction]

Let’s write the code by using the CLI from the VS Code terminal. You can create the asynchronous trigger by using the following command. You can then write the code with in this trigger block and push it to your org.

sfdx force:apex:trigger:create -n OpportunityChangeAsyncTrigger -s OpportunityChangeEvent -e 'after insert' -d 'force-app/main/default/triggers'

In this code, Trigger.new() contains list of change events after the database operation. In the for loop, we are extracting the Opportunity ID, which is processed to identify the high priority Account. The classifyAccount method of AccountClassifier class is very limit-intensive and computationally slow, hence we are calling it outside the transaction in this asynchronous trigger. You can also create this trigger from the Developer Console by selecting File→New→ Apex Trigger and then OpportunityChangeEvent for the sObject.

trigger OpportunityChangeAsyncTrigger on OpportunityChangeEvent (after insert) {
    List<OpportunityChangeEvent> changes = Trigger.new;
    
    Set<String> oppIds = new Set<String>();
    
    //Get all record Ids for this change and add it to a set for further processing
    for(OpportunityChangeEvent opp: changes){
        List<String> recordIds = opp.ChangeEventHeader.getRecordIds();
        oppIds.addAll(recordIds);
    }
    
    
    //Perform heavy computation operation which may take a lot of time
    AccountClassifier classifier = new AccountClassifier();
    Map<String, String> highPriorityAccounts = classifier.classifyAccount(new List<String>(oppIds));
}

With asynchronous Apex triggers, we can move complex computations and logic out of the transaction. The net effect is the transactions become faster and Apex limits consumption is reduced.

Resources

Leave your comments...

Get #Buildspiration with Asynchronous Apex Triggers in Summer ‘19