Platform Events in Apex
Spring this year brought longer days, shorter nights, new hope, and asynchronous publishing of Platform Events with the Salesforce Spring ‘21 Release.
Platform Events have been around for a few years, but as of the Spring ‘21 Release you can now run them asynchronously which is ideal for logging and to capture events that may be rolled back by a DML or callout failure.
This event-driven software architecture allows for sending of a notice that can be consumed by those listening for it.
These events can be captured, or subscribed to using :
External Apps with CometD client
These events can be published using :
Let’s look at an example that performs a callout to another firm’s system to validate a Contact’s email address and phone number, so we do not waste our salesperson’s time with bad information. Once we make the callout to their system we get a response with the data to update our Contact record.
Before we make that callout we publish a platform event in our Apex class to create a Log record showing that we made the callout to verify the data. We will use an Apex trigger to listen for the platform event and create that Log record.
Setting up the Platform Event
We need to create a custom platform event within Salesforce and add fields to that event. You will recognize this process as it mimics many of the steps in creating a custom object, custom metadata, or custom setting.
In Quick Find in the Setup menu, enter “Platform Events.”
Select the Option of Platform Events under Integrations.
Select the New Platform Event button.
Create a Label and Object Name.
Select a Publish Behavior of Publish Immediately.
We want to log events whether or not the code is successful. More information on the difference between the options can be found here.
Select the Save Button.
To create the custom event fields, select the New Button in the Custom Fields and Relationships page section. The type of fields are limited but should suffice in most instances.
I will create the following fields by walking through the wizard:
Response Status Code
The above fields all match the names, types, and lengths of the destination object that we will create the record in using an Apex trigger.
Creating the Trigger
Publish an Event
I chose to create a short Apex class to perform a callout, primarily because I could demonstrate its failure easily, but you can use any method to make the platform event.
If you are familiar with making callouts you need to set up the different endpoints as a Remote Site Setting in the Setup menu to authorize Salesforce to let code make a talk to a URL outside itself. If you do not setup this Remote Site Setting, Salesforce denies your code access and you get an ugly error. This first method simply makes a callout to an external URL, but before that, it makes a call to another Apex method to create a Log Event and publishes that Log Event record.
The difference between creating a Log Event and a Log record is that instead of using an insert command, the EventBus.publish command is used.
Run the Code
Now we will run our classes to publish a Log Event and create a Log record.
Open Execute Anonymous Window in the Developer Console.
In the popup window enter: “createCallout.callout();”.
Select the Execute Button.
You will see the following error message appear: System.CalloutException: Unauthorized endpoint, please check Setup->Security->Remote site settings. Endpoint = https://somethinghere.com
Select the OK button. Now navigate to the Logs Object, and you will see a log that was created despite the error.
Had we attempted to perform an insert of a Log record prior to the callout, it would have failed. Likewise, executing a DML (Data Manipulation Language) command prior to a callout would have resulted in an error in our debug logs of “System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out.”
The test class for the event is similar to that of any test class.
Above are two tests, a positive and a negative test.
The positive test creates a platform event and then publishes that event. The SaveResult is tested as being successful, and that a log was created.
The negative tests put values longer than the field length into the event. This results in an error. The SaveResult is tested for success and it is false and that the returned error message indicates that was ‘a value too large for the field’.
The asynchronous nature of the platform event allows you to create a broadcast of actions that can then be subscribed to and used both internally and externally in a separate thread which allows for scalability and higher governor limits. Salesforce’s documentation provides multiple examples of where this can be advantageous from a software firm having printer ink ordered based on information sent from a printer, or notifications of purchase orders that can be sent to fulfillment centers both with code and with tools such as Flows and Process Builder.
Things to Consider
The platform events are created by the user Automated Process which means that if you need the current information, you will need to add that to the event information. In the log example, we get the current user id as a string and update a Lookup field when we create the record in the trigger. If you want to see the event logs, you will need to set up the Automated Process user and enable logging for the user.
The fields type are limited to :
Text Area (Long)
Field-level security does not apply to the event, and fields are read-only by default.
Deleting an Event is permanent there is no undone.
Not supported in Professional Edition or Group Editions of Salesforce.