Example: Publish Callback Class That Correlates Callback Results with Event Messages
This example callback class implementation shows how to retry publishing failed events. It’s based on a trigger on the Order object.
Callback Class
If event publishing fails, the onFailure method in the FailureCallbackWithCorrelation class is invoked. This method retries publishing failed events up to two times. 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. Alternatively, you can use the record ID to obtain field data from the record and populate event fields. The example omits this detail for simplicity.
The examples in this section require a platform event, Order Event, to be defined with a Text(18) field of Order Id.
1public class FailureCallbackWithCorrelation implements EventBus.EventPublishFailureCallback2{3 public static final Integer MAX_RETRIES = 2;4 private Integer retryCounter = 0;5 private Map<String,String>uuidMap;67 // Callback constructor8 public FailureCallbackWithCorrelation(Map<String,String>uuidMap){9 this.uuidMap = uuidMap;10}1112 public void onFailure(EventBus.FailureResult result){13 List<String>eventUuids = result.getEventUuids();14 Map<String,String>newUuidMap = new Map<String,String>();1516 if(retryCounter<MAX_RETRIES){17 // Try to re-publish the failed events18 List<Order_Event__e>events = new List<Order_Event__e>();19 for(String uuid : eventUuids){20 // Create a new event with the contents of the failed event21 Order_Event__e event = (Order_Event__e)22 Order_Event__e.sObjectType.newSObject(null, true);23 // Fill event with the right order record Id24 event.Order_Id__c = uuidMap.get(uuid); 25 events.add(event);2627 // Use a new map since the new event will have a different uuid28 newUuidMap.put(event.EventUuid, event.Order_Id__c);29}30 // Replace old uuid map because we no longer need its contents31 uuidMap = newUuidMap;3233 // Republish with the same callback passed in again as 'this'34 System.debug('Republish ' + eventUuids.size() + ' failed events.');35 EventBus.publish(events, this); 36 System.debug('Republish event for Order with Ids: ' + 37 String.join(uuidMap.values(), ', '));3839 // Increase counter40 retryCounter++;41}else{42 // Retry exhausted, log an error instead43 System.debug(eventUuids.size() + ' event(s) failed to publish after ' + 44 MAX_RETRIES + ' retries ' +45 'for Order with Ids: ' + String.join(uuidMap.values(), ', '));46}47}4849 // Getter methods so we can validate this in the unit test50 public Integer getRetryCounter(){51 return retryCounter;52}5354 public Map<String,String>getUuidMap(){55 return uuidMap;56}57}
Apex Trigger
For each inserted or updated order record, the trigger publishes the Order_Event__e platform event with a populated EventUuid field.
1trigger OrderTrigger on Order(after insert, after update){2 Map<String,String>uuidMap = new Map<String,String>();3 List<Order_Event__e>events = new List<Order_Event__e>();45 for(Order o : Trigger.new){6 Order_Event__e e = (Order_Event__e)7 Order_Event__e.sObjectType.newSObject(null, true);8 // Fill event field with Order Id9 e.Order_Id__c = o.Id; 10 // Map event UUID -> Order Id so we can look up later11 uuidMap.put(e.EventUuid, o.Id); 12 events.add(e);13}1415 FailureCallbackWithCorrelation cb = new FailureCallbackWithCorrelation(uuidMap);16 List<Database.SaveResult>srs = EventBus.publish(events, cb);1718 // Inspect immediate publish result19 for(Database.SaveResult sr : srs){20 if(sr.isSuccess()){21 System.debug('Successfully enqueued event.');22}else{23 for(Database.Error err : sr.getErrors()){24 System.debug('Error returned: ' + err.getStatusCode() + ' - ' + 25 err.getMessage());26}27}28}29}
To run the trigger, insert an order record. Because an order depends on an account and contract, create these records first. You can create the records in the user interface or via Apex or an API. An Apex snippet is provided for your convenience. You can run this snippet in the Developer Console, in the Execute Anonymous Window.
1// Create account2Account a = new Account();3a.Name = 'Account Callback';4insert a;56// Create contract7Contract c = new Contract();8c.StartDate = Date.today();9c.ContractTerm = 12;10c.Status = 'Draft';11c.AccountId = a.Id;12insert c;1314// Create order15Order o = new Order();16o.AccountId = a.Id;17o.ContractId = c.Id;18o.Status = 'Draft';19o.EffectiveDate = Date.today();20insert o;