The core package (dndm) provides the fundamental abstractions for the DNDM library: Router, Intent, Interest, Link, Linker, Route, Peer, and Endpoint interfaces.
This package is designed for controlled environments where:
- The set of intents and interests is known at design time
- The set of clients/producers is known and controlled
- Primary use case is robotics internal message bus
- Runtime validation can be minimal (known routes, trusted environment)
- Security checks can be added later if needed (modular architecture)
These assumptions allow for:
- Simplified validation logic
- Performance optimizations (no excessive runtime checks)
- Easier addition of validation/security later (middleware pattern)
The Router is the top-level component that manages endpoints and routes intents/interests across them.
Current Implementation:
- Manages a collection of endpoints
- Routes intents/interests to appropriate routers
- Handles intent/interest aggregation across endpoints
Current Assumptions (Controlled Environment):
- Single router per process (typical use case)
- Endpoint failures are handled by application (known topology)
- Dynamic endpoint addition supported, but topology typically known
- Multiple publishers on same route are allowed (known, intentional setup)
- Routing policies can be added via middleware if needed
Key Questions:
Should Router support multiple routers in the same process?→ Not needed for controlled environmentHow should router handle endpoint failures?→ Application handles (known topology)- Should Router support dynamic endpoint addition/removal after initialization? → Supported but not primary use case
- How should Router handle conflicts when multiple endpoints publish to the same route? → Multiple publishers allowed (broadcast pattern)
- Should Router support routing policies? → Can be added via middleware if needed
Intent represents a source of data on a specific route. IntentRouter manages multiple intents and routes messages.
Components:
LocalIntent: Basic intent for local communicationFanOutIntent: Routes messages to multiple destinationsIntentRouter: Manages fan-out and wrapping
Current Implementation:
- LocalIntent uses channels for zero-copy message passing
- FanOutIntent distributes to multiple intents
- IntentRouter manages wrappers for multiple subscribers
Current Assumptions (Controlled Environment):
- Message priority/QoS not needed (known traffic patterns)
- Slow consumers handled by buffer size configuration (known topology)
- Message expiration/TTL not implemented (controlled environment, known producers)
- Partial failures handled at application level (known producers)
- Backpressure via channel blocking (simple, sufficient for known topology)
- Type mismatches are programming errors (caught at compile-time with protobuf)
Key Questions:
Should Intent support message priority or QoS levels?→ Not needed for robotics use case- How should Intent handle slow consumers? → Blocking channels (sufficient for known topology)
Should Intent support message expiration/TTL?→ Not needed (controlled environment)- How should IntentRouter handle partial failures? → Log and continue (application handles failures)
- Should Intent support backpressure mechanisms? → Channel blocking is sufficient
- How to handle type mismatches? → Programming error (compile-time with protobuf types)
Interest represents a consumer of data on a specific route. InterestRouter manages multiple interests and routes messages.
Components:
LocalInterest: Basic interest for local communicationFanInInterest: Routes messages from multiple sourcesInterestRouter: Manages fan-in and wrapping
Current Implementation:
- LocalInterest uses channels for message delivery
- FanInInterest aggregates from multiple interests
- InterestRouter manages wrappers for multiple publishers
Key Questions:
- Should Interest support message filtering/subscription filters?
- How should Interest handle message ordering? FIFO? Timestamp-based?
- Should Interest support message deduplication?
- How should InterestRouter handle duplicate messages from multiple sources?
- Should Interest support message batching/aggregation?
- How to handle type casting errors at runtime?
Link represents a connection between an Intent and an Interest.
Current Implementation:
- Creates channel connection between intent and interest
- Sends notifications when link is established
Key Questions:
- Should Link support multiple links for same intent/interest pair?
- How should Link handle link failures? Automatic retry?
- Should Link support link metrics (message count, latency)?
- How should Link handle link lifecycle events (callbacks)?
Linker manages Intent-Interest matching and link creation.
Current Implementation:
- Maintains maps of intents and interests
- Automatically links matching routes
- Supports wrapper functions for intent/interest customization
Key Questions:
- Should Linker support multiple linkers? Hierarchical linking?
- How should Linker handle link conflicts? Multiple intents for same route?
- Should Linker support link policies (e.g., only link if certain conditions met)?
- How should Linker handle link failures? Automatic cleanup?
- Should Linker support link notifications/events?
- How to handle race conditions between intent/interest registration?
Route represents a typed, named path for data streams.
Components:
PlainRoute: Human-readable route with type and pathHashedRoute: Opaque route for security
Current Implementation:
- Format:
Type@pathfor plain routes - Format:
prefix#hashfor hashed routes - Route validation and matching
Key Questions:
- Should Route support wildcards or pattern matching?
- How should Route handle versioning? Should we support route versioning?
- Should Route support metadata (e.g., QoS, priority)?
- How should hashed routes work in distributed systems? How to distribute keys?
- Should Route support route aliases or redirects?
- How to handle route collisions in mesh networks?
Peer represents a network peer with scheme, address, and path.
Current Implementation:
- URI-based peer identification:
scheme://address/path?params - Path-based prefix matching for routing
Key Questions:
- Should Peer support peer discovery mechanisms?
- How should Peer handle peer authentication/identity?
- Should Peer support peer capabilities/features negotiation?
- How should Peer handle peer lifecycle events (connect, disconnect)?
- Should Peer support peer metadata (e.g., location, capabilities)?
- How to handle peer path collisions?
Endpoint is an abstraction for communication mechanisms. Container aggregates multiple endpoints.
Current Implementation:
- BaseEndpoint provides common functionality
- Container manages multiple endpoints
- Supports endpoint lifecycle management
Key Questions:
- Should Container support endpoint priorities or ordering?
- How should Container handle endpoint failures? Remove? Retry?
- Should Container support endpoint health checks?
- How should Container handle endpoint configuration?
- Should Container support endpoint metrics/observability?
- How to handle routing conflicts between endpoints?
Base provides context management and lifecycle hooks.
Current Implementation:
- Context management with cancellation
- OnClose hooks for cleanup
Key Questions:
- Should Base support multiple context hierarchies?
- How should Base handle cleanup order? Should there be cleanup phases?
- Should Base support timeout configuration?
- How to handle cleanup failures?
-
Type Safety:
- How to improve type safety at API level?
- Should we support generics for type-safe wrappers?
- How to avoid runtime type assertions?
-
Error Handling:
- Should we use error channels instead of error returns?
- How to distinguish transient vs permanent errors?
- Should we support error callbacks?
-
Configuration:
- Should we support configuration builders?
- How to handle configuration validation?
- Should we support configuration inheritance?
-
Observability:
- Should we expose metrics?
- How to handle distributed tracing?
- Should we support event callbacks?
-
Zero-Copy:
- Can we use unsafe pointers for zero-copy?
- How to handle message serialization with minimal copying?
- Should we support memory pools?
-
Concurrency:
- How to minimize lock contention?
- Should we use lock-free data structures?
- How to handle goroutine leaks?
-
Buffering:
- How to size channels/buffers?
- Should we support dynamic buffering?
- How to handle backpressure?
- Race Conditions: Multiple goroutines accessing shared state without proper synchronization in some cases
- Resource Management: Some resources may not be properly cleaned up
- Error Propagation: Some errors are logged but not properly propagated
- Type Safety: Runtime type checking could be improved
- Add Metrics: Track message counts, latencies, error rates
- Improve Type Safety: Use generics where possible, add compile-time checks
- Better Error Handling: Distinguish error types, add error channels
- Performance Optimization: Reduce allocations, minimize copying
- Testing: Add more comprehensive tests, especially for concurrent scenarios
-
Unit Tests:
- Should we use table-driven tests?
- How to test concurrent behavior?
- How to test context cancellation?
-
Integration Tests:
- How to test Router with multiple endpoints?
- How to test mesh network behavior?
- How to test failure scenarios?
-
Performance Tests:
- What metrics should we benchmark?
- How to test under load?
- How to test memory usage?