Module Event System Consistency
Overview
The module event system is designed to be consistent, minimal, and extensible. All events follow a clear pattern and timing to ensure modules can integrate seamlessly with the node.
Event Timing and Consistency
ModuleLoaded Event
Key Principle: ModuleLoaded events are only published AFTER a module has subscribed (after startup is complete).
Flow:
- Module process is spawned
- Module connects via IPC and sends Handshake
- Module sends
SubscribeEventsrequest - At subscription time:
- Module receives
ModuleLoadedevents for all already-loaded modules (hotloaded modules get existing modules) ModuleLoadedis published for the newly subscribing module (if it’s loaded)
- Module receives
- Module is now fully operational
Why this design?
- Ensures
ModuleLoadedonly happens after module is fully ready (subscribed) - Hotloaded modules automatically receive all existing modules
- Consistent event ordering: subscription → ModuleLoaded
- No race conditions: modules can’t miss events
Example Flow
Startup (Module A loads first):
- Module A process spawned
- Module A connects and handshakes
- Module A subscribes to events
ModuleLoadedpublished for Module A (no other modules yet)
Hotload (Module B loads later):
- Module B process spawned
- Module B connects and handshakes
- Module B subscribes to events
- Module B receives
ModuleLoadedfor Module A (already loaded) ModuleLoadedpublished for Module B (all modules get it)
Unified Events
DataMaintenance (Unified Cleanup/Flush)
Replaces: StorageFlush and DataCleanup (unified into one extensible event)
Purpose: Single event for all data maintenance operations
Payload:
operation: “flush”, “cleanup”, or “both”urgency: “low”, “medium”, or “high”reason: “periodic”, “shutdown”, “low_disk”, “manual”target_age_days: Optional (for cleanup operations)timeout_seconds: Optional (for high urgency operations)
Usage Examples:
- Shutdown:
DataMaintenance { operation: "flush", urgency: "high", reason: "shutdown", timeout_seconds: Some(5) } - Periodic Cleanup:
DataMaintenance { operation: "cleanup", urgency: "low", reason: "periodic", target_age_days: Some(30) } - Low Disk:
DataMaintenance { operation: "both", urgency: "high", reason: "low_disk", target_age_days: Some(7), timeout_seconds: Some(10) }
Benefits:
- Single event for all maintenance operations
- Extensible: easy to add new operation types or urgency levels
- Clear semantics: operation + urgency + reason
- Modules can handle all maintenance in one place
Event Categories
1. Node Lifecycle
NodeStartupCompleted: Node is fully operationalNodeShutdown: Node is shutting down (modules should clean up)NodeShutdownCompleted: Shutdown finished
2. Module Lifecycle
ModuleLoaded: Module loaded and subscribed (after startup complete)ModuleUnloaded: Module unloadedModuleReloaded: Module reloadedModuleCrashed: Module crashed
3. Configuration
ConfigLoaded: Node configuration loaded/changed
4. Maintenance
DataMaintenance: Unified cleanup/flush event (replaces StorageFlush + DataCleanup)MaintenanceStarted: Maintenance operation startedMaintenanceCompleted: Maintenance operation completedHealthCheck: Health check performed
5. Resource Management
DiskSpaceLow: Disk space is lowResourceLimitWarning: Resource limit approaching
Best Practices
- Subscribe Early: Modules should subscribe to events as soon as possible after handshake
- Handle ModuleLoaded: Always handle
ModuleLoadedto know about other modules - DataMaintenance: Handle all maintenance operations in one place using
DataMaintenance - Graceful Shutdown: Always handle
NodeShutdownandDataMaintenance(urgency: “high”) - Non-Blocking: Keep event handlers fast and non-blocking
Consistency Guarantees
- ModuleLoaded Timing: Always happens after subscription (startup complete)
- Hotloaded Modules: Always receive all already-loaded modules
- Event Ordering: Consistent ordering (subscription → ModuleLoaded)
- No Race Conditions: Events are delivered reliably
- Unified Maintenance: Single event for all maintenance operations
Extensibility
The event system is designed to be easily extensible:
- Add New Events: Add to
EventTypeenum andEventPayloadenum - Add Event Publishers: Add methods to
EventPublisher - Add Event Handlers: Modules subscribe and handle events
- Unified Patterns: Follow existing patterns (e.g., DataMaintenance)
Migration from Old Events
Old: StorageFlush + DataCleanup
New: DataMaintenance with operation and urgency fields
Migration:
#![allow(unused)]
fn main() {
// Old
match event_type {
EventType::StorageFlush => { flush_data().await?; }
EventType::DataCleanup => { cleanup_data().await?; }
}
// New
match event_type {
EventType::DataMaintenance => {
if let EventPayload::DataMaintenance { operation, urgency, .. } = payload {
if operation == "flush" || operation == "both" {
flush_data().await?;
}
if operation == "cleanup" || operation == "both" {
cleanup_data().await?;
}
}
}
}
}
See Also
- Module System - Module system architecture
- Event System Integration - Complete integration guide
- Janitorial Events - Maintenance and lifecycle events
- Module IPC Protocol - IPC communication details