Get Asynchronous Publish Results with Apex Publish Callbacks
Learning Objectives
After completing this unit, you’ll be able to:
- Write an Apex publish callback class that handles failed events.
- Publish an event with a callback instance.
- Write a test class for the Apex publish callback class.
Use a Publish Callback Class and Inspect the Final Result
To catch the asynchronous publishing errors, Vijay from Cloud Kicks decides to use Apex publish callbacks. He implements a callback to capture the events that failed to publish and retry publishing them.
To write an Apex publish callback class, Vijay implements the EventBus.EventPublishFailureCallback
interface. The implemented onFailure
method contains logic to get the events that failed to publish and republishes them. The custom code limits the event republishing to two attempts. A map holds the UUID values of each published event and maps it to the order record ID. This mapping is used to populate the event Order_Id__c
field.
Add the Class in the Developer Console
- In the Developer Console, click New | Apex Class.
- For the class name, enter
FailureCallbackWithCorrelation
. - Replace the default code with this class body.
To execute the publish callback, publish some order events. But before that, let's make sure the debug logs are collected for the Automated Process user.
Add a Trace Flag for Automated Process for Debug Logs
A publish callback runs under the Automated Process user. To collect debug logs for the callback’s execution, add a trace flag for Automated Process.
Add a trace flag Entry for the Automated Process User:
- From Setup, in the Quick Find box, enter
Debug Logs
, then click Debug Logs. - Click New.
- For Traced Entity Type, select Automated Process.
- Select the time period to collect logs. The start and expiration dates default to the current date and time. To extend the expiration date, click the end date input box, and select the next day from the calendar.
- For Debug Level, click New Debug Level. Enter a name, such as
CustomDebugLevel
, and accept the defaults. - Save your work.
When the callback is invoked, it’s logged in the debug log. Logging for the callback requires the System
debug log level to be set to at least Info
. The default System
debug log level works because it is Debug
, which is more granular than Info
. When the callback is invoked, the debug log line looks as follows.
Create an Event with an EventUuid Field Value
Before publishing an event, let's create an event with a pre-populated EventUuid
field value. The EventUuid
field uniquely identifies an event message. You can use the EventUuid
field used to match the events returned in the publish callback with the events that were published in the EventBus.publish
call.
To have the system generate an EventUuid
field value in each event object, use the SObjectType.newSObject(recordTypeId, loadDefaults)
Apex method to create the event object, as follows.
Publish Events with a Callback Instance
After creating events using the newSObject
method, you can publish the events with a callback instance.
This code snippet creates two events and publishes them. The EventBus.publish
call references an instance of the callback class, FailureCallbackWithCorrelation
, which was defined earlier. It then checks for any immediate errors returned by the publish call. If there are any asynchronous errors, they cause the onFailure
method in the FailureCallbackWithCorrelation
class to run.
When you run the code snippet above in the Developer Console, you see the log output of the code snippet. The log output of the trigger is in Setup, in the Debug Logs page for the Automated Process user. However, in this case, because the publishing most likely succeeds, the onFailure
method isn't called and you won't see a log for the callback execution.
Because you can't simulate a system error, you can't cause the onFailure
method to run. However, you can use a test class to simulate an error and test the onFailure
. The test class is shown in the next section.
Test the Publish Callback Class
Vijay writes a test that simulates the failed publishing of a test event, which triggers the execution of the onFailure
callback method.
This method simulates a failed publishing of a test event or a batch of test events in an Apex test.
In an Apex test, event messages are published synchronously in the test event bus. The Test.getEventBus().fail()
method causes the publishing of events to fail immediately after the call, and event messages are removed from the test event bus. This method causes the onFailure
method in the callback class to be invoked. When the event messages fail to publish, none of the Apex triggers defined on the platform event receive any failed events.
To simulate successful event delivery, call the Test.getEventBus().deliver();
method or have your events delivered after Test.stopTest()
. Event messages are delivered immediately after each of those statements. Successfully delivered events cause the execution of the onSuccess
method in the callback class. The onSuccess
method isn't covered in this Trailhead module, but you can learn more about it in Deliver Test Event Messages in the Platform Events Developer Guide.
Test Class Example
Add this class in your Trailhead Playground in the same way you added the callback class earlier.
This example class, FailureCallbackWithCorrelationTest
, is a test class for the FailureCallbackWithCorrelation
class. This test class shows how to test the failed publishing of test event messages in the test event bus. The test first creates an event and publishes it with the callback. Next, the test fails the delivery of the event twice in a loop. The test verifies that the callback retries publishing the event twice by checking that the retryCounter
variable has been increased.
Run the Test Class in the Developer Console
- In the Developer Console, click Test | New Run.
- In the Test Classes column, select FailureCallbackWithCorrelationTest.
- Select the test, and then click Run.
- Double-click the completed test run to open the results in detail view. You can verify that the test succeeded.
- To verify that the callback
onFailure
method was invoked, open the debug log. Click the Logs tab and double-click the latest log entry. The debug log shows that the events were republished twice and failed publishing. This is an excerpt of some operations logged in the debug log.
For more information and for code examples, see Test Apex Publish Callbacks in the Platform Events Developer Guide.
Publish Callback Best Practices
Keep in mind these best practices when implementing Apex publish callbacks.
- Don’t republish the same event object that is created with
SObjectType.newSObject.
- Publish a list of events instead of individual events with a callback.
- Don’t use the SObject generic type when publishing a list of events. Instead, use the specific platform event type as the data type in the list.
- To reduce the callback instance size, keep the map of event UUIDs small in the callback. A small callback instance size ensures better performance and helps avoid hitting the cumulative usage limit of all publish callbacks. The
FailureCallbackWithCorrelation
class in this unit maps the event UUID to a record ID that you can query to populate the remaining event fields. Alternatively, if you want to save the entire event as the map value, make sure that the event doesn't have many fields and the field sizes are small. - Be mindful when tracking successful publishes through the
onSuccess
method. Because most publish calls typically succeed, tracking successful publishes likely isn’t a concern. If a large volume of events is published, processing successful publishes can have performance and Apex limit impacts. We recommend that you process successful publishes only when absolutely necessary. The performance impact doesn't apply to processing failed publishes through theonFailure
method because failed publish calls occur rarely.
For more information about these best practices, see Publish Callback Best Practices in the Platform Events Developer Guide.
You now know how to use Apex publish callbacks and how to test them. Publishing events is only half the story. Writing subscribers that receive events is the other half. In the next unit, you learn best practices for writing robust and resilient platform event triggers.
Resources
- Salesforce Help: Developer Console
- Salesforce Help: Create a Test Run
- Platform Events Developer Guide: Get the Result of Asynchronous Platform Event Publishing with Apex Publish Callbacks
- Platform Events Developer Guide: Test Apex Publish Callbacks
- Platform Events Developer Guide: Publish Callback Best Practices
- Platform Events Developer Guide: Apex Publish Callback Limits