Messaging & queue patterns
Purpose: Integrate AEM with enterprise messaging (Kafka/JMS/webhooks) without turning AEM into a message broker.
Who this page is for
| Audience | Why it matters to you |
|---|---|
| Backend engineers | Async integration builders |
| Architects | Boundary decisions |
First principle
AEM has an internal queue (Sling Jobs — at-least-once, per-instance) fit for AEM's own async work. It is not an enterprise message bus. When other systems need events reliably, put a real broker/gateway between AEM and them.
Outbound: AEM emits events
content event (plan published)
→ ResourceChangeListener/replication event (author)
→ Sling Job ("emit-plan-event") ← retry + persistence inside AEM
→ HTTP POST to gateway/bridge ← thin, dumb delivery
→ broker (Kafka/queue) ← fan-out, retention, consumers
Rules: emit thin events (IDs + paths, consumers fetch details via the content API); one emission point (the job consumer), not scattered POSTs; idempotency keys because Sling Jobs may deliver twice; the bridge/gateway owns broker credentials — AEM speaks HTTPS only, keeping broker libraries out of OSGi.
Inbound: systems push to AEM
| Pattern | Verdict |
|---|---|
| Webhook servlet on AUTHOR (writes content via service user) | ✔ standard — validate signature, respond 202 fast, process in a Sling Job |
| Polling upstream on a schedule | ✔ simplest, right for daily/hourly data (sync pattern) |
| AEM as a Kafka consumer (client in OSGi) | ⚠ possible, painful: partition rebalancing vs instance lifecycle, offset ownership across author failover — prefer a bridge that converts to webhooks |
| Direct repository writes from outside (JCR remoting, ad hoc packages) | ✗ bypasses validation, audit, replication discipline |
Delivery semantics recap
Every hop is at-least-once somewhere: design consumers idempotent end-to-end (upsert by natural key — plan ID — not insert). Ordering: don't depend on it across paths; sequence numbers in payloads where order matters.