cuddle-please 11d659dbd7
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
chore(release): 0.8.0
2025-08-07 09:30:44 +00:00
2025-07-24 22:44:13 +02:00
2024-08-06 22:22:46 +02:00
2024-08-06 22:22:46 +02:00
2025-08-07 11:29:29 +02:00
2025-08-07 09:30:44 +00:00
2025-08-07 09:30:44 +00:00
2025-08-07 11:29:29 +02:00
2025-08-07 11:29:29 +02:00
2024-11-24 00:26:37 +01:00

MAD - Lifecycle Manager for Rust Applications

Crates.io Documentation License: MIT

Overview

MAD is a robust lifecycle manager designed for long-running Rust operations. It provides a simple, composable way to manage multiple concurrent services within your application, handling graceful startup and shutdown automatically.

Perfect for:

  • 🌐 Web servers
  • 📨 Queue consumers and message processors
  • 🔌 gRPC servers
  • Cron job runners
  • 🔄 Background workers
  • 📡 Any long-running async operations

Features

  • Component-based architecture - Build your application from composable, reusable components
  • Graceful shutdown - Automatic handling of shutdown signals with proper cleanup
  • Concurrent execution - Run multiple components in parallel with tokio
  • Error handling - Built-in error propagation and logging
  • Cancellation tokens - Coordinate shutdown across all components
  • Minimal boilerplate - Focus on your business logic, not lifecycle management

Installation

Add MAD to your Cargo.toml:

[dependencies]
notmad = "0.7.5"
tokio = { version = "1", features = ["full"] }
async-trait = "0.1"

Quick Start

Here's a simple example of a component that simulates a long-running server:

use mad::{Component, Mad};
use async_trait::async_trait;
use tokio_util::sync::CancellationToken;

// Define your component
struct WebServer {
    port: u16,
}

#[async_trait]
impl Component for WebServer {
    fn name(&self) -> Option<String> {
        Some(format!("WebServer on port {}", self.port))
    }

    async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> {
        println!("Starting web server on port {}", self.port);
        
        // Your server logic here
        // The cancellation token will be triggered on shutdown
        tokio::select! {
            _ = cancellation.cancelled() => {
                println!("Shutting down web server");
            }
            _ = self.serve() => {
                println!("Server stopped");
            }
        }
        
        Ok(())
    }
}

impl WebServer {
    async fn serve(&self) {
        // Simulate a running server
        tokio::time::sleep(std::time::Duration::from_secs(3600)).await;
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Build and run your application
    Mad::builder()
        .add(WebServer { port: 8080 })
        .add(WebServer { port: 8081 })  // You can add multiple instances
        .run()
        .await?;

    Ok(())
}

Advanced Usage

Custom Components

Components can be anything that implements the Component trait:

use mad::{Component, Mad};
use async_trait::async_trait;

struct QueueProcessor {
    queue_name: String,
}

#[async_trait]
impl Component for QueueProcessor {
    fn name(&self) -> Option<String> {
        Some(format!("QueueProcessor-{}", self.queue_name))
    }

    async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> {
        while !cancellation.is_cancelled() {
            // Process messages from queue
            self.process_next_message().await?;
        }
        Ok(())
    }
}

Error Handling

MAD provides comprehensive error handling through the MadError type with automatic conversion from anyhow::Error:

async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> {
    // Errors automatically convert from anyhow::Error to MadError
    database_operation().await?;
    
    // Or return explicit errors
    if some_condition {
        return Err(anyhow::anyhow!("Something went wrong").into());
    }
    
    Ok(())
}

Examples

Check out the examples directory for more detailed examples:

  • basic - Simple component lifecycle
  • fn - Using functions as components
  • signals - Handling system signals
  • error_log - Error handling and logging

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Author

Created and maintained by kjuulh

Repository

Find the source code at https://github.com/kjuulh/mad

Description
No description provided
Readme 332 KiB
v0.7.5 Latest
2025-07-24 22:44:58 +02:00
Languages
Rust 100%