10 KiB
Event-Driven Architecture Guide
Source: Salesforce Architect Decision Guides — Event-Driven Architecture, Async Processing Related: event-patterns.md | callout-patterns.md
Overview
Event-Driven Architecture (EDA) decouples producers from consumers, enabling scalable, resilient integrations. Salesforce supports multiple event mechanisms — choosing the right one depends on volume, latency, and consumer location.
5 Core EDA Patterns
Pattern Comparison Matrix
| Pattern | Description | Salesforce Implementation | Best For |
|---|---|---|---|
| Pub/Sub | Publisher emits, multiple subscribers consume | Platform Events + Pub/Sub API | Multi-consumer notifications, cross-system sync |
| Fanout | One event → multiple independent consumers | Platform Events + multiple subscribers | Parallel processing, diverse downstream systems |
| Passed Messages | Event carries data payload for consumer processing | Platform Events with rich fields | External systems needing full context in message |
| Streaming | Continuous data feed for real-time consumers | CDC + Pub/Sub API | Data replication, real-time dashboards |
| Queueing | Ordered, guaranteed-delivery message processing | Platform Events (High-Volume) with checkpoints | Sequential processing, backpressure handling |
When to Use Each
Pub/Sub: Default choice for most event-driven integrations. Works for both internal (Apex triggers) and external (Pub/Sub API) consumers.
Fanout: When a single business event (e.g., "Order Placed") needs to notify billing, shipping, analytics, and notifications simultaneously.
Passed Messages: When the consumer needs all context in the event itself (no callback to Salesforce). Keep payloads lean — 1 MB limit.
Streaming: For data replication to warehouses or lakes. CDC + Pub/Sub API replaces legacy Streaming API.
Queueing: When processing order matters and you need backpressure handling. Use High-Volume Platform Events with resume checkpoints.
Pub/Sub API (Recommended External Subscription)
The Pub/Sub API is the recommended mechanism for external consumers subscribing to Platform Events and CDC events. It replaces the legacy Streaming API (CometD).
Key Characteristics
| Feature | Pub/Sub API | Legacy Streaming API (Deprecated) |
|---|---|---|
| Protocol | gRPC | CometD (long-polling) |
| Authentication | OAuth 2.0 | Session-based |
| Event Types | Platform Events, CDC, Custom Channels | PushTopic, Generic Events, Platform Events |
| Performance | High throughput, binary protocol | Limited by long-polling overhead |
| Status | Current — use for all new development | Deprecated — no new investments |
Subscription Modes
- Subscribe: Stream events from a given replay ID forward
- PublishStream: Bi-directional — publish events via gRPC (no Apex needed)
- ManagedSubscribe: Salesforce manages replay state (simplest for external consumers)
External Consumer Architecture
Salesforce Org
└── Platform Event / CDC Event
└── Pub/Sub API (gRPC endpoint)
└── External Consumer (Java, Python, Node.js, Go)
├── Process event
├── Commit replay ID
└── Handle failures with retry
LWC Subscription (Internal)
For Lightning Web Components subscribing to Platform Events, use empApi:
import { subscribe, unsubscribe, onError } from 'lightning/empApi';
const channelName = '/event/Order_Status__e';
let subscription = {};
connectedCallback() {
subscribe(channelName, -1, (response) => {
console.log('Event received:', JSON.stringify(response));
this.handleEvent(response.data.payload);
}).then((sub) => {
subscription = sub;
});
onError((error) => {
console.error('empApi error:', JSON.stringify(error));
});
}
disconnectedCallback() {
unsubscribe(subscription);
}
Event Relays to AWS EventBridge
Salesforce Event Relays forward Platform Events to AWS EventBridge, enabling cloud-native event processing.
Architecture
Salesforce Platform Event
└── Event Relay Definition (Metadata)
└── AWS EventBridge Partner Event Source
├── AWS Lambda
├── AWS SQS
├── AWS Step Functions
└── Any EventBridge target
When to Use
- AWS-native architecture needing Salesforce events
- Complex event processing requiring AWS services (Step Functions, SQS, SNS)
- Fan-out to multiple AWS consumers from a single Salesforce event
- Event archival in AWS S3 or data lakes
Limitations
- One-way only (Salesforce → AWS)
- Adds latency (~seconds) compared to direct Pub/Sub API
- Requires AWS account configuration and IAM setup
- Platform Event limits still apply on the Salesforce side
Apache Kafka on Heroku
For organizations needing long-retention, high-throughput event streaming beyond Platform Event limits.
Comparison with Platform Events
| Feature | Platform Events | Kafka on Heroku |
|---|---|---|
| Retention | 24h (HV) / 72h (SV) | 1-6 weeks (configurable) |
| Throughput | Millions/day (HV) | Millions/second |
| Consumer groups | Limited | Unlimited |
| Replay | ReplayId-based | Offset-based, topic-level |
| Cost | Included / Platform Event add-on | Heroku Kafka add-on |
When to Choose Kafka
- Retention > 72 hours required
- Need multiple independent consumer groups
- Event throughput exceeds Platform Event limits
- Existing Kafka ecosystem in organization
- Need topic partitioning for ordered processing
Integration Pattern
Salesforce → Platform Event → Apex/Flow subscriber → Heroku Kafka producer
└── Consumer Group A (analytics)
└── Consumer Group B (data lake)
└── Consumer Group C (external CRM)
When NOT to Use Events
Events are not always the right choice. Prefer synchronous patterns when:
| Scenario | Why Not Events | Better Alternative |
|---|---|---|
| Need synchronous response | Events are async — no return value | REST callout with Named Credential |
| Infrequent data changes | Event infrastructure overhead not justified | Scheduled batch sync |
| Target system lacks event support | Consumer can't subscribe to events | Outbound Messages or REST callout |
| Simple record sync | Over-engineering for basic needs | Salesforce Connect / External Objects |
| Data volume < 100 records/day | Platform Event overhead unnecessary | Scheduled Flow with REST callout |
High-Volume Outbound Pattern
For scenarios requiring high-volume data push to external systems:
Do NOT use async Apex directly for high-volume outbound. Apex async limits (250K daily Queueable, 250K daily @future) are shared across all org operations. Consuming them for outbound sync starves other automation.
Recommended Pattern: Middleware + Platform Events
Salesforce Record Change
└── After-Save Flow / Trigger
└── Publish Platform Event (lightweight payload)
└── External Middleware (MuleSoft, Pub/Sub API consumer)
├── Enrich data (callback to Salesforce REST API if needed)
├── Transform to target format
├── Deliver to target system with retry logic
└── Report status back via Platform Event or REST callback
Benefits
- No Apex async limit consumption — events don't count against daily limits
- Middleware handles retries — exponential backoff, dead letter queues
- Scalable — middleware scales independently of Salesforce
- Observable — middleware provides logging, monitoring, alerting
Monitoring Event-Driven Systems
AsyncApexJob Monitoring
Query job status for async Apex that processes events:
List<AsyncApexJob> jobs = [
SELECT Id, JobType, Status, NumberOfErrors, MethodName, CreatedDate
FROM AsyncApexJob
WHERE CreatedDate = TODAY
AND Status IN ('Failed', 'Aborted')
ORDER BY CreatedDate DESC
LIMIT 50
];
Polling limit: AsyncApexJob queries are subject to SOQL limits. Max polling frequency: every 5 minutes.
Platform Event Metrics
- Setup → Platform Events → Usage: View publish/subscribe counts
- EventBusSubscriber: Query for subscriber status and position
- Proactive Monitoring: Set up Flow or Apex to alert on failed event processing
// Check subscriber lag
List<EventBusSubscriber> subs = [
SELECT Name, Position, Retries, LastError, Status
FROM EventBusSubscriber
WHERE Topic = 'Order_Status__e'
];
Key Metrics to Monitor
| Metric | Source | Alert Threshold |
|---|---|---|
| Failed events | EventBusSubscriber.Retries |
> 3 consecutive retries |
| Subscriber lag | EventBusSubscriber.Position vs latest ReplayId |
Lag > 1000 events |
| Async job failures | AsyncApexJob.NumberOfErrors |
Any failure |
| Event publish errors | Database.SaveResult in publisher |
Any failure |
| Daily event usage | Setup → Company Information → Platform Event Usage | > 80% of allocation |
Summary: EDA Decision Tree
Need real-time data sync?
├── YES → Is consumer external?
│ ├── YES → Pub/Sub API + Platform Events (or CDC for record changes)
│ └── NO → Platform Event trigger subscriber (or empApi for LWC)
└── NO → Is volume high (>10K records/day)?
├── YES → Middleware + Platform Events (high-volume outbound pattern)
└── NO → Scheduled batch sync (simplest, most maintainable)