The Unified Event Space
In Happen, events flow seamlessly across process, network, and environment boundaries through a unified NATS backbone. This approach eliminates the artificial boundaries typically found in distributed systems, enabling you to build applications that span multiple processes and environments with the same simplicity as local ones.
Beyond Boundaries
Happen's unified event space means you write code the same way regardless of where nodes are deployed:
// The exact same code works whether nodes are:
// - In the same process
// - In different processes on the same machine
// - Distributed across different machines
// - In completely different environments (server, browser, edge)
orderNode.send(inventoryNode, {
type: "check-inventory",
payload: { orderId: "123", items: [...] }
});
This isn't just an API convenience—it's a fundamental design principle that creates location transparency throughout your system. Nodes can be deployed wherever makes the most sense for your architecture, and your code remains unchanged.
How the Unified Event Space Works
At the heart of Happen's unified event space is the NATS messaging system with its JetStream persistence layer. When an event crosses boundaries:
The event is automatically serialized using MessagePack
NATS delivers it to the appropriate destination
The event is deserialized on arrival
The receiving node processes it using standard event handlers
All of this happens transparently—your code simply uses send()
and on()
without needing to know whether communication is local or remote.
Cross-Boundary Serialization
When events cross process or network boundaries in Happen, they are efficiently handled through a streamlined serialization strategy:
JSON Interface, Binary Transport
Happen provides a natural JSON-like interface for developers while using efficient binary serialization under the hood:
Developer Experience: Work with standard JavaScript objects in your code
Transport Efficiency: MessagePack binary format used for actual transmission
Transparent Conversion: Serialization/deserialization happens automatically
No Schema Required: Maintains Happen's schema-free flexibility
This approach gives you the best of both worlds - the simplicity of working with native JavaScript objects and the efficiency of binary transport.
Preserving Causality Across Boundaries
One of the most powerful aspects of Happen's unified event space is how it maintains causality across boundaries. Every event carries its complete causal context:
// When an event crosses a boundary, its context is preserved
{
type: "inventory-reserved",
payload: {
orderId: "order-123",
items: [/* ... */]
},
context: {
causal: {
id: "evt-789", // Unique event ID
sender: "inventory-node", // Originating node
causationId: "evt-456", // Event that caused this one
correlationId: "txn-123", // Transaction this belongs to
path: [ // Complete journey
["user-node", "order-node"],
["order-node", "inventory-node"]
]
}
}
}
This causal context creates a complete web of relationships that spans your entire distributed system.
Unified Configuration
Happen provides a clean, explicit approach to configuration that separates environment concerns from application logic:
// Initialize Happen with NATS as the universal backbone
const happen = initializeHappen({
// NATS configuration
nats: {
// Connection configuration
connection: {
// Server environment (direct NATS)
server: {
servers: ['nats://server:4222'],
jetstream: true
},
// Browser environment (WebSocket)
browser: {
servers: ['wss://server:8443'],
jetstream: true
}
},
// Enable key features
capabilities: {
// Persistence through JetStream
persistence: {
enabled: true,
// Use Key-Value store for state
keyValue: {
enabled: true,
buckets: {
state: "happen-state",
temporal: "happen-temporal"
}
}
},
// Delivery guarantees
delivery: {
exactlyOnce: true,
deduplication: true
}
}
}
});
Node-Level Configuration
Individual nodes can specify their own delivery requirements:
// Node with specific reliability requirements
const paymentNode = createNode("payment-service", {
// Delivery guarantees for this specific node
delivery: {
exactlyOnce: true,
acknowledge: true,
timeout: 5000, // ms
retries: 3
}
});
Large Payload Management
For handling large data across boundaries, Happen leverages NATS Key-Value store to provide a global namespace:
The Global Namespace
// Store large data
const key = `data:${generateId()}`;
node.global.set(key, largeData);
// Reference in events
node.send(targetNode, {
type: "process-data",
payload: { dataKey: key }
});
// Retrieve on the other side
const data = await targetNode.global.get(event.payload.dataKey);
Handling Network Realities
Real-world networks are unreliable. Happen's NATS-based transport layer addresses these realities directly:
Persistent Delivery
Events can be stored in JetStream's durable storage until successfully processed, ensuring:
Durability: Events survive process restarts
Guaranteed Delivery: Events reach their destination even after network issues
Natural Backpressure: JetStream provides backpressure for overloaded consumers
Network Partitions
During network partitions:
Nodes continue operating within their connected segments
Events destined for disconnected nodes are stored in JetStream
When connectivity resumes, stored events are delivered
Causality is preserved throughout this process
This happens automatically through JetStream's durable storage capabilities.
Cross-Environment Communication
The unified transport system makes cross-environment communication seamless:
// Server-side node sending to browser client
serverNode.on("update-client", (event) => {
// Use the standard send method - routing happens automatically
serverNode.send(browserNode, {
type: "data-updated",
payload: event.payload.data
});
});
Benefits of the Unified Event Space
This approach to distributed events creates powerful capabilities:
Location Transparency: Your code doesn't need to know or care where nodes are deployed
Protocol Flexibility: The right protocol is selected automatically for each environment
Environment Adaptability: Seamlessly bridge between server, browser, and edge environments
Deployment Freedom: Components can move between environments by simply changing deployment configuration
Resilient Architecture: Systems naturally handle network fluctuations through JetStream
Future Extensibility: Easily adopt new NATS capabilities as they become available
By providing a truly unified event space powered by NATS, Happen enables you to focus on your application's domain rather than the complexities of distributed systems.
Last updated