Platform Events & Event-Driven Architecture

0/9 in this phase0/41 across the roadmap

📖 Concept

Platform Events are Salesforce's implementation of an event-driven messaging system. They enable loosely coupled communication between components, orgs, and external systems.

What Platform Events solve:

  1. Decoupling — Components communicate without direct dependencies
  2. Async processing — Events are processed asynchronously
  3. Cross-boundary communication — Salesforce to external, external to Salesforce
  4. Avoiding governor limits — Each subscriber gets its own transaction
  5. Audit trail — Events can be replayed (last 72 hours)

Platform Events vs other messaging:

Platform Events   — Custom events you define. Publish/subscribe model.
Change Data Capture — Automatic events when records change (insert/update/delete/undelete).
Streaming API      — Push notifications for record changes (PushTopic, Generic Events).
Outbound Messaging — Legacy. Sends SOAP messages on workflow rules.

Key characteristics:

  • Events are published to Salesforce's event bus
  • Multiple subscribers can listen to the same event
  • Subscribers can be: Apex triggers, Flows, LWC, CometD clients (external)
  • Events are fire-and-forget — the publisher doesn't know who subscribes
  • Events persist for 72 hours (replayable)
  • Each event trigger gets its own governor limits

Change Data Capture (CDC): Automatically publishes events when standard or custom object records are created, updated, deleted, or undeleted. You don't write publish code — just subscribe.

CDC vs Platform Events:

  • CDC: Automatic, captures ALL changes to subscribed objects
  • Platform Events: Manual publish, custom payloads, semantic meaning

When to use Platform Events:

  • Integration: Decouple Salesforce from external systems
  • Complex automations: Break governor limit chains
  • Audit/logging: Record events without blocking the main transaction
  • Cross-org communication: Publish events to external subscribers via CometD

💻 Code Example

codeTap to expand ⛶
1// Platform Events — Complete Implementation
2
3// 1. Publishing Platform Events
4public class EventPublisher {
5
6 // Publish a single event
7 public static void publishOrderEvent(Order__c order) {
8 Order_Event__e event = new Order_Event__e(
9 Order_Id__c = order.Id,
10 Account_Id__c = order.Account__c,
11 Total_Amount__c = order.Total_Amount__c,
12 Status__c = order.Status__c,
13 Event_Type__c = 'ORDER_CREATED'
14 );
15
16 Database.SaveResult sr = EventBus.publish(event);
17 if (!sr.isSuccess()) {
18 for (Database.Error err : sr.getErrors()) {
19 System.debug('Event publish error: ' + err.getMessage());
20 }
21 }
22 }
23
24 // Publish multiple events (bulk)
25 public static void publishBulkEvents(List<Order__c> orders) {
26 List<Order_Event__e> events = new List<Order_Event__e>();
27
28 for (Order__c order : orders) {
29 events.add(new Order_Event__e(
30 Order_Id__c = order.Id,
31 Account_Id__c = order.Account__c,
32 Total_Amount__c = order.Total_Amount__c,
33 Status__c = order.Status__c,
34 Event_Type__c = 'ORDER_UPDATED'
35 ));
36 }
37
38 List<Database.SaveResult> results = EventBus.publish(events);
39
40 Integer successCount = 0;
41 for (Database.SaveResult sr : results) {
42 if (sr.isSuccess()) successCount++;
43 }
44 System.debug('Published ' + successCount + '/' + events.size() + ' events');
45 }
46
47 // Publish from a trigger (decouple processing)
48 public static void publishFromTrigger(List<Case> cases) {
49 List<Case_Escalation__e> events = new List<Case_Escalation__e>();
50
51 for (Case c : cases) {
52 if (c.Priority == 'High' && c.Status == 'Escalated') {
53 events.add(new Case_Escalation__e(
54 Case_Id__c = c.Id,
55 Priority__c = c.Priority,
56 Account_Id__c = c.AccountId,
57 Escalation_Reason__c = c.Reason
58 ));
59 }
60 }
61
62 if (!events.isEmpty()) {
63 EventBus.publish(events);
64 }
65 }
66}
67
68// 2. Subscribing to Platform Events (Apex Trigger)
69// trigger OrderEventTrigger on Order_Event__e (after insert) {
70// OrderEventHandler.handleEvents(Trigger.new);
71// }
72
73public class OrderEventHandler {
74
75 public static void handleEvents(List<Order_Event__e> events) {
76 List<Task> tasksToCreate = new List<Task>();
77 Set<Id> accountIds = new Set<Id>();
78
79 for (Order_Event__e event : events) {
80 if (event.Event_Type__c == 'ORDER_CREATED' &&
81 event.Total_Amount__c > 50000) {
82
83 accountIds.add(event.Account_Id__c);
84
85 tasksToCreate.add(new Task(
86 Subject = 'Large order received: $' + event.Total_Amount__c,
87 WhatId = event.Order_Id__c,
88 Priority = 'High',
89 ActivityDate = Date.today()
90 ));
91 }
92 }
93
94 if (!tasksToCreate.isEmpty()) {
95 // Assign tasks to account owners
96 Map<Id, Account> accounts = new Map<Id, Account>(
97 [SELECT Id, OwnerId FROM Account WHERE Id IN :accountIds]
98 );
99
100 for (Task t : tasksToCreate) {
101 // ... assign owner
102 }
103
104 insert tasksToCreate;
105 }
106
107 // Set replay ID checkpoint for error recovery
108 // EventBus.TriggerContext.currentContext().setResumeCheckpoint(
109 // events[events.size() - 1].ReplayId
110 // );
111 }
112}
113
114// 3. Change Data Capture — Subscribe to record changes
115// trigger AccountChangeEventTrigger on AccountChangeEvent (after insert) {
116// AccountCDCHandler.handleChanges(Trigger.new);
117// }
118
119public class AccountCDCHandler {
120
121 public static void handleChanges(List<AccountChangeEvent> changes) {
122 for (AccountChangeEvent event : changes) {
123 EventBus.ChangeEventHeader header = event.ChangeEventHeader;
124
125 String changeType = header.getChangeType(); // CREATE, UPDATE, DELETE, UNDELETE
126 List<String> changedFields = header.getChangedFields();
127 List<String> recordIds = header.getRecordIds();
128
129 System.debug('Change Type: ' + changeType);
130 System.debug('Changed Fields: ' + changedFields);
131 System.debug('Record IDs: ' + recordIds);
132
133 if (changeType == 'UPDATE' && changedFields.contains('Industry')) {
134 // React to Industry field changes
135 // Sync to external system, update related records, etc.
136 }
137 }
138 }
139}

🏋️ Practice Exercise

Platform Events Practice:

  1. Create a custom Platform Event (Order_Event__e) with 5 fields representing an order
  2. Write a publisher class that fires events from an Opportunity trigger when stage reaches 'Closed Won'
  3. Create an Apex trigger subscriber that creates follow-up Tasks from the events
  4. Subscribe to the event using Lightning Web Components (empApi)
  5. Enable Change Data Capture for Account and Contact, write a subscriber trigger
  6. Implement an event-driven integration: Salesforce publishes events, an external system subscribes via CometD
  7. Build a retry mechanism using Platform Events — failed operations publish retry events
  8. Create a real-time notification system using Platform Events and LWC
  9. Design an event-driven architecture that breaks a complex automation into 3 separate event chains
  10. Test Platform Events using Test.getEventBus().deliver() in unit tests

⚠️ Common Mistakes

  • Assuming Platform Events are transactional — they are NOT rolled back if the publishing transaction fails AFTER the event is published (unless using setSavepoint before publish)

  • Not setting resume checkpoints in event triggers — without checkpoints, missed events during failures cannot be replayed

  • Publishing too many events in a single transaction — limit is 150,000 published events per hour per org

  • Not handling event delivery failures — event triggers can fail and retry; use setResumeCheckpoint to avoid reprocessing

  • Confusing Platform Events with Change Data Capture — Platform Events are custom with explicit publish; CDC is automatic for tracked object changes

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for Platform Events & Event-Driven Architecture. Login to unlock this feature.