2 Commits

Author SHA1 Message Date
cuddle-please
11d659dbd7 chore(release): 0.8.0
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-08-07 09:30:44 +00:00
762da1e672 feat: update readme
All checks were successful
continuous-integration/drone/push Build is passing
Signed-off-by: kjuulh <contact@kjuulh.io>
2025-08-07 11:29:29 +02:00
5 changed files with 150 additions and 28 deletions

View File

@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.8.0] - 2025-08-07
### Added
- update readme
## [0.7.5] - 2025-07-24 ## [0.7.5] - 2025-07-24
### Added ### Added

2
Cargo.lock generated
View File

@@ -278,7 +278,7 @@ dependencies = [
[[package]] [[package]]
name = "notmad" name = "notmad"
version = "0.7.4" version = "0.7.5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",

View File

@@ -3,7 +3,7 @@ members = ["crates/*"]
resolver = "2" resolver = "2"
[workspace.package] [workspace.package]
version = "0.7.5" version = "0.8.0"
[workspace.dependencies] [workspace.dependencies]
mad = { path = "crates/mad" } mad = { path = "crates/mad" }

163
README.md
View File

@@ -1,39 +1,92 @@
# MAD # MAD - Lifecycle Manager for Rust Applications
Mad is a life-cycle manager for long running rust operations. [![Crates.io](https://img.shields.io/crates/v/notmad.svg)](https://crates.io/crates/notmad)
[![Documentation](https://docs.rs/notmad/badge.svg)](https://docs.rs/notmad)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
- Webservers ## Overview
- Queue bindings
- gRPC servers etc
- Cron runners
It is supposed to be the main thing the application runs, and everything from it is spawned and managed by it. 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`:
```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:
```rust ```rust
struct WaitServer {} use mad::{Component, Mad};
use async_trait::async_trait;
use tokio_util::sync::CancellationToken;
// Define your component
struct WebServer {
port: u16,
}
#[async_trait] #[async_trait]
impl Component for WaitServer { impl Component for WebServer {
fn name(&self) -> Option<String> { fn name(&self) -> Option<String> {
Some("NeverEndingRun".into()) Some(format!("WebServer on port {}", self.port))
} }
async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> { async fn run(&self, cancellation: CancellationToken) -> Result<(), mad::MadError> {
let millis_wait = rand::thread_rng().gen_range(50..1000); println!("Starting web server on port {}", self.port);
// Simulates a server running for some time. Is normally supposed to be futures blocking indefinitely // Your server logic here
tokio::time::sleep(std::time::Duration::from_millis(millis_wait)).await; // The cancellation token will be triggered on shutdown
tokio::select! {
_ = cancellation.cancelled() => {
println!("Shutting down web server");
}
_ = self.serve() => {
println!("Server stopped");
}
}
Ok(()) Ok(())
} }
} }
impl WebServer {
async fn serve(&self) {
// Simulate a running server
tokio::time::sleep(std::time::Duration::from_secs(3600)).await;
}
}
#[tokio::main] #[tokio::main]
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
// Build and run your application
Mad::builder() Mad::builder()
.add(WaitServer {}) .add(WebServer { port: 8080 })
.add(WaitServer {}) .add(WebServer { port: 8081 }) // You can add multiple instances
.add(WaitServer {})
.run() .run()
.await?; .await?;
@@ -41,11 +94,75 @@ async fn main() -> anyhow::Result<()> {
} }
``` ```
## Advanced Usage
### Custom Components
Components can be anything that implements the `Component` trait:
```rust
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`:
```rust
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 ## Examples
Can be found (here)[crates/mad/examples] Check out the [examples directory](crates/mad/examples) for more detailed examples:
- basic - **basic** - Simple component lifecycle
- fn - **fn** - Using functions as components
- signals - **signals** - Handling system signals
- error_log - **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](LICENSE) file for details.
## Author
Created and maintained by [kjuulh](https://github.com/kjuulh)
## Repository
Find the source code at [https://github.com/kjuulh/mad](https://github.com/kjuulh/mad)

View File

@@ -1,6 +1,6 @@
# yaml-language-server: $schema=https://git.front.kjuulh.io/kjuulh/cuddle/raw/branch/main/schemas/base.json # yaml-language-server: $schema=https://git.kjuulh.io/kjuulh/cuddle/raw/branch/main/schemas/base.json
base: "git@git.front.kjuulh.io:kjuulh/cuddle-rust-lib-plan.git" base: "git@git.kjuulh.io:kjuulh/cuddle-rust-lib-plan.git"
vars: vars:
service: "mad" service: "mad"
@@ -12,6 +12,6 @@ please:
repository: "mad" repository: "mad"
branch: main branch: main
settings: settings:
api_url: "https://git.front.kjuulh.io" api_url: "https://git.kjuulh.io"
actions: actions:
rust: rust: