| Crates.io | listen_signal |
| lib.rs | listen_signal |
| version | 0.1.15 |
| created_at | 2025-12-12 07:03:41.250978+00 |
| updated_at | 2025-12-12 13:26:05.369238+00 |
| description | A simple, cross-platform utility to gracefully handle process termination signals (SIGTERM, SIGINT, SIGQUIT). 一个简洁、跨平台的工具库,用于优雅地处理进程终止信号 (SIGTERM, SIGINT, SIGQUIT)。 |
| homepage | https://github.com/js0-site/rust/tree/dev/listen_signal |
| repository | https://github.com/js0-site/rust.git |
| max_upload_size | |
| id | 1981092 |
| size | 60,197 |
listen_signal is a lightweight Rust library that simplifies graceful shutdown for asynchronous applications. It provides stream-based signal handling for common termination signals (SIGTERM, SIGINT, SIGQUIT, SIGHUP) across Unix-like systems.
Add to your Cargo.toml:
[dependencies]
listen_signal = "0.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
futures = "0.3"
use listen_signal::wait;
use futures::StreamExt;
#[tokio::main]
async fn main() {
let mut signals = wait(&listen_signal::STOP);
tokio::select! {
signal = signals.next() => {
println!("Received signal: {:?}", signal);
}
_ = run_application() => {
println!("Application completed normally");
}
}
}
async fn run_application() {
// Your application logic here
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}
}
use listen_signal::wait;
use futures::StreamExt;
#[tokio::main]
async fn main() {
let mut signals = wait(&listen_signal::SINGAL_LI);
loop {
tokio::select! {
signal = signals.next() => {
match signal {
Some(listen_signal::SIGHUP) => {
println!("Reloading configuration...");
// Reload config without stopping
}
Some(_) => {
println!("Shutting down gracefully...");
break;
}
None => break,
}
}
_ = run_server() => {}
}
}
}
async fn run_server() {
// Server logic
}
wait()pub fn wait(li: impl AsRef<[i32]>) -> SignalsInfo
Creates a signal stream that listens for the specified signals. Returns a SignalsInfo stream that yields signal numbers.
Parameters:
li - List of signal numbers to monitor (can use predefined constants)Returns:
SignalsInfo - Async stream of received signalsPanics:
pub use signal_hook::consts::{SIGHUP, SIGINT, SIGQUIT, SIGTERM};
Individual signal constants:
SIGTERM (15) - Termination request (systemctl stop, docker stop, kill)SIGINT (2) - Interrupt from terminal (Ctrl+C)SIGQUIT (3) - Quit from terminal (Ctrl+\)SIGHUP (1) - Hangup / Reload request (systemctl reload)pub const STOP: [i32; 3]
Standard termination signals: [SIGTERM, SIGINT, SIGQUIT]
pub const SINGAL_LI: [i32; 4]
Termination and reload signals: [SIGTERM, SIGINT, SIGQUIT, SIGHUP]
graph TD
A[Application Start] --> B[call wait with signal list]
B --> C[Create SignalsInfo Stream]
C --> D[tokio::select! Block]
D --> E[Application Logic]
D --> F[signals.next]
F --> G{Wait for Signal}
G -->|Signal Received| H[Process Signal]
H --> I{SIGHUP?}
I -->|Yes| J[Reload Config]
I -->|No| K[Application Cleanup]
J --> F
K --> L[Process Exit]
E -->|Complete| M[Normal Exit]
The library implements a stream-based signal handling approach:
signal-hook to register OS signal handlerswait() returns a SignalsInfo stream via signal-hook-tokioStreamExt::next() to await signals asynchronouslytokio::select! macro for concurrent task managementlisten_signal/
├── Cargo.toml # Package manifest and dependencies
├── src/
│ └── lib.rs # Main library implementation
├── tests/
│ └── main.rs # Integration tests with signal injection
└── readme/
├── en.md # English documentation
└── zh.md # Chinese documentation
UNIX signals were introduced in Version 7 Unix (1979) by Dennis Ritchie and Ken Thompson. The signal mechanism provided a way for the kernel to notify processes of asynchronous events - from hardware exceptions to user interrupts.
The original signal API was notoriously difficult to use correctly due to race conditions and platform inconsistencies. POSIX.1-1990 standardized sigaction() to address these issues, introducing more reliable semantics.
SIGTERM (signal 15) was designed as the "polite" termination request - giving processes time to cleanup before exit. In contrast, SIGKILL (signal 9) forces immediate termination without cleanup. This distinction became crucial for containerized environments: Docker's docker stop sends SIGTERM, waits 10 seconds, then sends SIGKILL.
Modern async runtimes like Tokio brought new challenges to signal handling - signals are synchronous C callbacks, but Rust's async code requires thread-safe, future-aware notification. Projects like signal-hook emerged to bridge this gap, providing safe primitives for integrating UNIX signals with async ecosystems.
The principle of graceful shutdown - catching signals, closing connections, flushing buffers, saving state - has become a cornerstone of reliable distributed systems. What started as a kernel notification mechanism in 1979 now orchestrates the lifecycle of microservices across global infrastructure.
This project is an open-source component of js0.site ⋅ Refactoring the Internet Plan.
We are redefining the development paradigm of the Internet in a componentized way. Welcome to follow us:
listen_signal 是轻量级 Rust 库,用于简化异步应用的优雅关闭流程。基于信号流(stream)模式处理常见终止信号(SIGTERM、SIGINT、SIGQUIT、SIGHUP),支持类 Unix 系统。
在 Cargo.toml 中添加依赖:
[dependencies]
listen_signal = "0.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
futures = "0.3"
use listen_signal::wait;
use futures::StreamExt;
#[tokio::main]
async fn main() {
let mut signals = wait(&listen_signal::STOP);
tokio::select! {
signal = signals.next() => {
println!("收到信号: {:?}", signal);
}
_ = run_application() => {
println!("应用正常结束");
}
}
}
async fn run_application() {
// 应用业务逻辑
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}
}
use listen_signal::wait;
use futures::StreamExt;
#[tokio::main]
async fn main() {
let mut signals = wait(&listen_signal::SINGAL_LI);
loop {
tokio::select! {
signal = signals.next() => {
match signal {
Some(listen_signal::SIGHUP) => {
println!("重新加载配置...");
// 重载配置而不停止服务
}
Some(_) => {
println!("开始优雅关闭...");
break;
}
None => break,
}
}
_ = run_server() => {}
}
}
}
async fn run_server() {
// 服务器逻辑
}
wait()pub fn wait(li: impl AsRef<[i32]>) -> SignalsInfo
创建一个监听指定信号的信号流。返回 SignalsInfo 流,该流会产生信号编号。
参数:
li - 要监听的信号编号列表(可使用预定义常量)返回值:
SignalsInfo - 接收信号的异步流Panic:
pub use signal_hook::consts::{SIGHUP, SIGINT, SIGQUIT, SIGTERM};
独立信号常量:
SIGTERM (15) - 终止请求(systemctl stop、docker stop、kill)SIGINT (2) - 终端中断(Ctrl+C)SIGQUIT (3) - 终端退出(Ctrl+\)SIGHUP (1) - 挂起/重载请求(systemctl reload)pub const STOP: [i32; 3]
标准终止信号:[SIGTERM, SIGINT, SIGQUIT]
pub const SINGAL_LI: [i32; 4]
终止和重载信号:[SIGTERM, SIGINT, SIGQUIT, SIGHUP]
graph TD
A[应用启动] --> B[调用 wait 传入信号列表]
B --> C[创建 SignalsInfo 流]
C --> D[tokio::select! 块]
D --> E[应用业务逻辑]
D --> F[signals.next]
F --> G{等待信号}
G -->|收到信号| H[处理信号]
H --> I{是 SIGHUP?}
I -->|是| J[重载配置]
I -->|否| K[应用清理资源]
J --> F
K --> L[进程退出]
E -->|完成| M[正常退出]
本库采用基于流的信号处理方案:
signal-hook 注册操作系统信号处理器wait() 通过 signal-hook-tokio 返回 SignalsInfo 流StreamExt::next() 异步等待信号tokio::select! 宏,支持并发任务管理listen_signal/
├── Cargo.toml # 包清单和依赖配置
├── src/
│ └── lib.rs # 主库实现
├── tests/
│ └── main.rs # 集成测试(信号注入)
└── readme/
├── en.md # 英文文档
└── zh.md # 中文文档
UNIX 信号机制由 Dennis Ritchie 和 Ken Thompson 在第 7 版 Unix(1979 年)中引入。信号机制为内核提供了向进程通知异步事件的方式——从硬件异常到用户中断。
早期的信号 API 因竞态条件和平台不一致性而难以正确使用。POSIX.1-1990 标准化了 sigaction() 以解决这些问题,引入了更可靠的语义。
SIGTERM(信号 15)被设计为"礼貌的"终止请求——给进程时间进行清理后退出。相比之下,SIGKILL(信号 9)强制立即终止而不进行清理。这种区别在容器化环境中变得至关重要:Docker 的 docker stop 发送 SIGTERM,等待 10 秒后发送 SIGKILL。
像 Tokio 这样的现代异步运行时给信号处理带来了新挑战——信号是同步的 C 回调,而 Rust 的异步代码需要线程安全、future 感知的通知机制。signal-hook 等项目应运而生,为将 UNIX 信号集成到异步生态系统提供了安全原语。
优雅关闭原则——捕获信号、关闭连接、刷新缓冲区、保存状态——已成为可靠分布式系统的基石。从 1979 年的内核通知机制开始,如今已发展为编排全球基础设施中微服务生命周期的核心技术。
本项目为 js0.site ⋅ 重构互联网计划 的开源组件。
我们正在以组件化的方式重新定义互联网的开发范式,欢迎关注: