#graceful-shutdown #shutdown #graceful #async

meltdown

A lightweight service manager to help with graceful shutdown of asynchronous applications

5 releases (3 breaking)

0.3.0 Nov 3, 2024
0.2.0 Mar 1, 2023
0.1.1 Jan 28, 2023
0.1.0 Dec 20, 2022
0.0.0 Nov 21, 2021

#375 in Asynchronous

Download history 1/week @ 2024-07-29 13/week @ 2024-09-23 16/week @ 2024-09-30 14/week @ 2024-10-07 118/week @ 2024-10-28 38/week @ 2024-11-04

160 downloads per month

0BSD license

18KB
272 lines

Meltdown

A lightweight service manager to help with graceful shutdown of asynchronous applications.

Overview

Meltdown provides a simple way to manage multiple asynchronous services and coordinate their graceful shutdown. Perfect for web servers, background workers, or any async application that needs clean shutdown handling.

Features

  • Lightweight - Minimal dependencies and simple implementation
  • Runtime Agnostic - Works with any async runtime (tokio, async-std, smol, etc.)
  • Flexible - Works with any async service that can handle shutdown signals
  • Simple API - Easy to use with plain async functions and custom service types

Quick Start

Add this to your Cargo.toml:

[dependencies]
meltdown = "0.3.0"

Basic usage example with tokio and axum:

use axum::{routing, Router};
use meltdown::{Meltdown, Token};

async fn api_service(token: Token) -> Result<(), Box<dyn std::error::Error>> {
    let router = Router::new().route("/", routing::get("Hello!"));
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?;

    axum::serve(listener, router)
        .with_graceful_shutdown(token)
        .await
        .map_err(Into::into)
}

async fn signal_service(token: Token) -> Result<(), Box<dyn std::error::Error>> {
    tokio::select! {
        () = token => Ok(()),
        result = tokio::signal::ctrl_c() => result.map_err(Into::into),
    }
}

#[tokio::main]
async fn main() {
    let mut meltdown = Meltdown::new()
        .register(api_service)
        .register(signal_service);

    // Trigger shutdown when first service completes
    if let Some(result) = meltdown.next().await {
        println!("Got {result:?}, shutting down");
        meltdown.trigger();
    }

    // Wait for remaining services
    while let Some(result) = meltdown.next().await {
        println!("Got {result:?}");
    }
}

For detailed usage and examples, check out the documentation.

License

Licensed under the 0BSD license.

Dependencies

~0.6–0.8MB
~15K SLoC