Events
Contents
Send and listen to local or cluster wide events
Introduction
The XP framework enable developers to create and/or listen to events. Events may be local (within a single server) or cluster wide (distributed to all servers within a cluster). In addition to application specific events, XP itself produces a range of standard events.
Use cases
The use cases for events are limitless, but the most common are:
-
Cache invalidation
-
Notifications (i.e. notify clients connected to any server in the cluster via Websocket)
-
Job triggering
Local vs distributed semantics
-
send({distributed: false})(default) — fires only on the node that produced the event; use for in-process signalling like per-node cache eviction. -
send({distributed: true})— broadcasts to every member of the cluster; use for cross-node cache invalidation, multi-node WebSocket fanout, or any side effect that has to run on every node. -
listener({localOnly: true})— filters out events that originated on a remote node; use when a side effect should run exactly once on the originating node. -
The event object’s
localOriginanddistributedflags let a listener branch on origin withoutlocalOnly.
|
Event delivery is best-effort and fire-and-forget — no persistence, no replay, no acknowledgement. A node that is down or partitioned at broadcast time misses the event entirely. |
Threading and ordering
`Each event is handed to a single event worker thred before walking the listener list, so the publishing thread returns as soon as the event is queued.
-
Listeners must not block — the dispatch thread is shared, and a slow listener backs up every other listener on the node.
-
On a single node, FIFO holds — events published in sequence on the same node are delivered in that order to a listener that matches both.
-
Across cluster nodes events from the same nodes are ordered but from different nodes can arrive in either order on any third node.
-
Order between listeners is unspecified.
Standard event catalog
| Type pattern | Origin | What it signals |
|---|---|---|
|
|
core-repo |
Node lifecycle: |
|
|
core-repo |
Repository lifecycle: |
|
|
core-task |
Task lifecycle: |
|
|
core-app |
Application install / start / stop and cluster install events; the action — |
|
|
user code |
Anything published through lib-event’s |
Custom event naming
Custom events go through eventLib.send(…), which prepends custom. automatically — send({type: 'foo'}) is delivered as custom.foo. Namespace by application key to avoid collisions when multiple apps share a cluster.
import eventLib from '/lib/xp/event';
eventLib.send({
type: 'com.example.app.somethingHappened',
distributed: true,
data: { id: 'abc-123' }
});
// delivered as 'custom.com.example.app.somethingHappened'
Common patterns
Cluster-wide cache invalidation
A write on any node evicts the affected key on every node.
eventLib.listener({
type: 'custom.com.example.app.cache.invalidate',
callback: (event) => cache.delete(event.data.key as string)
});
eventLib.send({
type: 'com.example.app.cache.invalidate',
distributed: true,
data: { key }
});
WebSocket fanout across the cluster
A producer on any node can push to clients connected to whichever node terminated their socket.
eventLib.listener({
type: 'custom.com.example.app.feed.message',
callback: (event) => websocketLib.sendToGroup('live-feed', JSON.stringify(event.data))
});
eventLib.send({
type: 'com.example.app.feed.message',
distributed: true,
data: { message }
});
Library
For implementation details, please visit the event library documentation.