-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
Overview
The Go implementation has a ReadyDoneAware interface that provides a standard way for components to signal their ready and done states. This is essential for coordinating component lifecycle in complex systems.
Background
Reference implementation: skipgraph-go/modules/component.go
Components need to signal:
- Ready: Initialization complete, ready to process requests
- Done: Shutdown complete, no longer processing
Requirements
1. Define ReadyDoneAware Trait
use tokio::sync::watch;
/// Trait for components that have ready and done lifecycle states
pub trait ReadyDoneAware: Send + Sync {
/// Returns a receiver that will be notified when component is ready.
/// The channel should send true when ready.
/// Must be callable multiple times, returning clones of the same receiver.
fn ready(&self) -> watch::Receiver<bool>;
/// Returns a receiver that will be notified when component is done.
/// The channel should send true when done.
/// Must be callable multiple times, returning clones of the same receiver.
fn done(&self) -> watch::Receiver<bool>;
}2. Provide Default Implementation Helper
/// Helper struct to manage ready/done state
#[derive(Clone)]
pub struct LifecycleState {
ready_tx: watch::Sender<bool>,
ready_rx: watch::Receiver<bool>,
done_tx: watch::Sender<bool>,
done_rx: watch::Receiver<bool>,
}
impl LifecycleState {
pub fn new() -> Self {
let (ready_tx, ready_rx) = watch::channel(false);
let (done_tx, done_rx) = watch::channel(false);
Self { ready_tx, ready_rx, done_tx, done_rx }
}
/// Signal that the component is ready
pub fn signal_ready(&self) {
let _ = self.ready_tx.send(true);
}
/// Signal that the component is done
pub fn signal_done(&self) {
let _ = self.done_tx.send(true);
}
}
impl ReadyDoneAware for LifecycleState {
fn ready(&self) -> watch::Receiver<bool> {
self.ready_rx.clone()
}
fn done(&self) -> watch::Receiver<bool> {
self.done_rx.clone()
}
}3. Usage Example
pub struct MyComponent {
lifecycle: LifecycleState,
// other fields
}
impl MyComponent {
pub fn new() -> Self {
Self {
lifecycle: LifecycleState::new(),
}
}
pub async fn initialize(&self) {
// Do initialization work
self.lifecycle.signal_ready();
}
pub async fn shutdown(&self) {
// Do cleanup work
self.lifecycle.signal_done();
}
}
impl ReadyDoneAware for MyComponent {
fn ready(&self) -> watch::Receiver<bool> {
self.lifecycle.ready()
}
fn done(&self) -> watch::Receiver<bool> {
self.lifecycle.done()
}
}Design Considerations
- Use tokio::sync::watch for efficient multi-consumer notifications
- Channels must be clonable for multiple observers
- State transitions are one-way (not ready→ready, not done→done)
- Components should handle the case where observers never arrive
Testing
- Test state transitions
- Test multiple observers
- Test concurrent access
- Test with async components
Dependencies
- tokio (for watch channels)
Priority
High - This is required before implementing the Component trait
Related Issues
- Depends on: Implement ThrowableContext for Error Propagation #52 (ThrowableContext)
- Blocks: Component trait implementation
Metadata
Metadata
Assignees
Labels
No labels