| Crates.io | moosicbox_async_service |
| lib.rs | moosicbox_async_service |
| version | 0.1.4 |
| created_at | 2024-10-04 02:47:50.338607+00 |
| updated_at | 2025-07-21 19:14:46.604388+00 |
| description | MoosicBox async service package |
| homepage | |
| repository | https://github.com/MoosicBox/MoosicBox |
| max_upload_size | |
| id | 1395983 |
| size | 45,107 |
Asynchronous service management framework for the MoosicBox ecosystem, providing basic service lifecycle management, command processing, and task execution utilities for building concurrent applications.
Add this to your Cargo.toml:
[dependencies]
moosicbox_async_service = "0.1.1"
use moosicbox_async_service::*;
// Define your command types
#[derive(Debug)]
pub enum MyCommand {
ProcessData { data: String },
GetStatus,
Shutdown,
}
// Define your service context
pub struct MyContext {
pub processed_count: u32,
pub status: String,
}
// Use the async_service_body macro to generate the service
async_service_body!(MyCommand, MyContext, true); // true = sequential processing
// Implement the Processor trait
impl Processor for Service {
type Error = Box<dyn std::error::Error + Send + Sync>;
async fn process_command(
ctx: Arc<tokio::sync::RwLock<MyContext>>,
command: MyCommand,
) -> Result<(), Self::Error> {
match command {
MyCommand::ProcessData { data } => {
println!("Processing: {}", data);
let mut context = ctx.write().await;
context.processed_count += 1;
context.status = format!("Processed: {}", data);
}
MyCommand::GetStatus => {
let context = ctx.read().await;
println!("Status: {} (count: {})", context.status, context.processed_count);
}
MyCommand::Shutdown => {
println!("Shutting down service");
}
}
Ok(())
}
async fn on_start(&mut self) -> Result<(), Self::Error> {
println!("Service starting");
Ok(())
}
async fn on_shutdown(
ctx: Arc<tokio::sync::RwLock<MyContext>>,
) -> Result<(), Self::Error> {
println!("Service shutting down");
Ok(())
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create service context
let context = MyContext {
processed_count: 0,
status: "Ready".to_string(),
};
// Create and start the service
let service = Service::new(context)
.with_name("MyDataProcessor");
let handle = service.handle();
let join_handle = service.start();
// Send commands to the service
handle.send_command_async(MyCommand::ProcessData {
data: "Hello World".to_string()
}).await?;
handle.send_command_async(MyCommand::GetStatus).await?;
// Send command and wait for completion
handle.send_command_and_wait_async(MyCommand::ProcessData {
data: "Important Data".to_string()
}).await?;
// Shutdown the service
handle.shutdown()?;
// Wait for service to complete
join_handle.await??;
Ok(())
}
// Sequential processing (commands processed one at a time)
async_service_body!(MyCommand, MyContext, true);
// Concurrent processing (commands processed in parallel)
async_service_body!(MyCommand, MyContext, false);
use moosicbox_async_service::CommanderError;
match handle.send_command_async(command).await {
Ok(()) => println!("Command sent successfully"),
Err(CommanderError::Send) => eprintln!("Failed to send command"),
Err(CommanderError::Recv(e)) => eprintln!("Receive error: {}", e),
}
The main service struct that manages command processing and lifecycle.
A cloneable handle for sending commands to the service from other tasks.
Provides methods for sending commands:
send_command(): Send without waitingsend_command_async(): Send asynchronously without waitingsend_command_and_wait_async(): Send and wait for completionDefine how your service processes commands and handles lifecycle events.
The library re-exports commonly used async utilities:
tokio: Async runtime and utilitiesasync_trait: Async trait supportflume: Fast async channelsfutures: Additional async utilitiesmoosicbox_task: Task spawning utilitiesThis framework provides a foundation for building robust async services in the MoosicBox ecosystem.