State Management
State management in Happen provides powerful capabilities through minimal abstractions. This guide explores patterns and approaches for effectively managing state across your Happen applications.
Core Principles
Happen's approach to state management follows these foundational principles:
Clear Ownership: Each node owns and is responsible for its specific state
Functional Transformations: State changes occur through pure functional transformations
Event-Driven Updates: State typically changes in response to events
Decentralized Intelligence: Nodes make autonomous decisions based on their local state
Composition Over Complexity: Complex state management emerges from composing simple patterns
Under the hood, Happen uses NATS JetStream's Key-Value store to provide durable, distributed state storage with high consistency guarantees.
Basic State Operations
Accessing State
Happen provides a clean, functional approach to accessing state:
// Access the complete state
const orderState = orderNode.state.get();
// Access with transformation (focused state access)
const activeOrders = orderNode.state.get(state =>
(state.orders || {}).filter(order => order.status === "active")
);Transforming State
State transformations use a functional approach:
Composing Transformations
You can compose transformations for cleaner code:
View System
Views provide a window into other nodes' state, enabling coordinated operations across node boundaries.
Basic View Usage
Enhanced Collection
For more efficient collection of state from multiple nodes, use the collect pattern:
This approach:
Traverses the node graph only once
Collects specific slices of state from each relevant node
Transforms the state during collection
Returns a unified object with all the collected data
Scaling Patterns
As your application grows, these patterns help manage increasing state complexity.
Selective State Access
Access only what you need to minimize memory footprint:
Domain Partitioning
Partition state across multiple domain-specific nodes:
Each node maintains state for its specific domain, communicating via events when necessary.
Event-Driven State Synchronization
Use events to communicate state changes between nodes:
Chunked Processing
For large state objects, process in manageable chunks:
Advanced Patterns
State Versioning
Track state versions for debugging and auditing:
Computed State
Define computed values based on raw state:
State-Based Event Generation
Generate events based on state conditions:
NATS JetStream Key-Value Store Integration
Under the hood, Happen uses NATS JetStream's Key-Value store capability to provide durable, distributed state storage. The framework handles all the details of storing and retrieving state, ensuring:
Persistence: State is preserved even if nodes or processes restart
Distributed Access: State can be accessed across different processes and machines
Consistency: State updates maintain causal ordering
Performance: High-performance storage with minimal overhead
This integration happens transparently - your code uses the same state API regardless of where nodes are running or how state is stored.
Best Practices
Keep State Focused
Each node should maintain state relevant to its domain:
Use Immutable Patterns
Always update state immutably to maintain predictability:
Prefer Event Communication
Use events to communicate state changes between nodes:
Let Event Flow Drive State Changes
Instead of directly modifying state in response to external conditions, let events drive state changes:
By focusing on clear ownership, functional transformations, and event-driven communication, you can create systems that are both powerful and maintainable. The integration with NATS JetStream's Key-Value store provides a robust foundation for distributed state management without adding complexity to your application code.
Last updated