Platform Events & Event-Driven Architecture
📖 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:
- Decoupling — Components communicate without direct dependencies
- Async processing — Events are processed asynchronously
- Cross-boundary communication — Salesforce to external, external to Salesforce
- Avoiding governor limits — Each subscriber gets its own transaction
- 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
1// Platform Events — Complete Implementation23// 1. Publishing Platform Events4public class EventPublisher {56 // Publish a single event7 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 );1516 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 }2324 // Publish multiple events (bulk)25 public static void publishBulkEvents(List<Order__c> orders) {26 List<Order_Event__e> events = new List<Order_Event__e>();2728 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 }3738 List<Database.SaveResult> results = EventBus.publish(events);3940 Integer successCount = 0;41 for (Database.SaveResult sr : results) {42 if (sr.isSuccess()) successCount++;43 }44 System.debug('Published ' + successCount + '/' + events.size() + ' events');45 }4647 // 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>();5051 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.Reason58 ));59 }60 }6162 if (!events.isEmpty()) {63 EventBus.publish(events);64 }65 }66}6768// 2. Subscribing to Platform Events (Apex Trigger)69// trigger OrderEventTrigger on Order_Event__e (after insert) {70// OrderEventHandler.handleEvents(Trigger.new);71// }7273public class OrderEventHandler {7475 public static void handleEvents(List<Order_Event__e> events) {76 List<Task> tasksToCreate = new List<Task>();77 Set<Id> accountIds = new Set<Id>();7879 for (Order_Event__e event : events) {80 if (event.Event_Type__c == 'ORDER_CREATED' &&81 event.Total_Amount__c > 50000) {8283 accountIds.add(event.Account_Id__c);8485 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 }9394 if (!tasksToCreate.isEmpty()) {95 // Assign tasks to account owners96 Map<Id, Account> accounts = new Map<Id, Account>(97 [SELECT Id, OwnerId FROM Account WHERE Id IN :accountIds]98 );99100 for (Task t : tasksToCreate) {101 // ... assign owner102 }103104 insert tasksToCreate;105 }106107 // Set replay ID checkpoint for error recovery108 // EventBus.TriggerContext.currentContext().setResumeCheckpoint(109 // events[events.size() - 1].ReplayId110 // );111 }112}113114// 3. Change Data Capture — Subscribe to record changes115// trigger AccountChangeEventTrigger on AccountChangeEvent (after insert) {116// AccountCDCHandler.handleChanges(Trigger.new);117// }118119public class AccountCDCHandler {120121 public static void handleChanges(List<AccountChangeEvent> changes) {122 for (AccountChangeEvent event : changes) {123 EventBus.ChangeEventHeader header = event.ChangeEventHeader;124125 String changeType = header.getChangeType(); // CREATE, UPDATE, DELETE, UNDELETE126 List<String> changedFields = header.getChangedFields();127 List<String> recordIds = header.getRecordIds();128129 System.debug('Change Type: ' + changeType);130 System.debug('Changed Fields: ' + changedFields);131 System.debug('Record IDs: ' + recordIds);132133 if (changeType == 'UPDATE' && changedFields.contains('Industry')) {134 // React to Industry field changes135 // Sync to external system, update related records, etc.136 }137 }138 }139}
🏋️ Practice Exercise
Platform Events Practice:
- Create a custom Platform Event (Order_Event__e) with 5 fields representing an order
- Write a publisher class that fires events from an Opportunity trigger when stage reaches 'Closed Won'
- Create an Apex trigger subscriber that creates follow-up Tasks from the events
- Subscribe to the event using Lightning Web Components (empApi)
- Enable Change Data Capture for Account and Contact, write a subscriber trigger
- Implement an event-driven integration: Salesforce publishes events, an external system subscribes via CometD
- Build a retry mechanism using Platform Events — failed operations publish retry events
- Create a real-time notification system using Platform Events and LWC
- Design an event-driven architecture that breaks a complex automation into 3 separate event chains
- 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.