如何让RUST运行优雅的在后台守护?
How to make RUST run gracefully in the background and daemonize?
这就是我想要实现的
root> ./webserver start // Does not block the terminal after startup, runs in the background and the process is guarded
root>
我目前的实现逻辑:
后台逻辑 运行ning
use std::process::Command;
use std::thread;
use std::env;
use std::time::Duration;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() == 2 {
if &args[1] == "start" {
// Main process start child process
let child = Command::new(&args[0])
.spawn().expect("Child process failed to start.");
println!("child pid: {}", child.id());
// Main process exit
}
} else {Is there any more elegant approach? Looking forward to your reply
// Main business logic
run webserver
}
}
这样rust会在后台运行不阻塞终端,但是rust在后台打印的信息仍然会显示在终端上,退出时会退出当前的rust程序航站楼
进程守护逻辑
我的想法是监听系统的退出信号,不处理退出请求
SIGHUP 1 /* Hangup (POSIX). */
SIGINT 2 /* Interrupt (ANSI). */
SIGQUIT 3 /* Quit (POSIX). */
SIGTERM 15 /* Termination (ANSI). */
代码:
use signal_hook::{iterator::Signals, SIGHUP,SIGINT,SIGQUIT,SIGTERM};
use std::{thread, time::Duration};
pub fn process_daemon() {
let signals = match Signals::new(&[SIGHUP,SIGINT,SIGQUIT,SIGTERM]) {
Ok(t) => t,
Err(e) => panic!(e),
};Is there any more elegant approach? Looking forward to your reply
thread::spawn(move || {
for sig in signals.forever() {
println!("Received signal {:?}", sig);
}
});
thread::sleep(Duration::from_secs(2));
}
有没有更优雅的做法?期待您的回复。
TLDR:如果您真的希望您的进程像服务一样运行(并且从不退出),可能需要设置一个服务管理器。否则,就让它成为一个正常的过程。
守护进程
立即注意到的一件事是 大多数 关于守护进程的考虑与 Rust 作为一种语言无关,更多的是关于:
- 您的进程所针对的底层系统
- 您的守护进程在生成后的确切行为
看了你的问题,你似乎已经意识到了大部分。不幸的是,为了正确回答您的问题,我们必须深入研究流程的复杂性及其管理方式。应该注意的是,如果您可以在启动基础架构中使用重要的平台 依赖性 ,那么现有的 'service' 管理器是一个很好的解决方案。
正如您所看到的,如果您想要一个可以正常工作的简单部署(前提是它是为相关系统编译的),这绝非易事。这些只是裸机服务管理器。如果你想支持虚拟环境,你将不得不考虑 Kubernetes 服务、dockerizing 等。
存在这些工具是因为在系统上管理长 运行ning 进程有很多考虑因素:
- 我的守护进程是否应该像服务一样运行并在被杀死(或系统重新启动)时重生?上面的工具将允许这样做。
- 如果是一项服务,我的守护程序是否应该具有与其关联的状态以帮助维护?这有助于管理中断和构建工具以横向扩展。
- 如果守护进程不应该是一个服务(在你的情况下不太可能给出你的二进制文件的名称)还有更多的问题:它应该附加到父进程吗?是否应该附加到登录进程组?
鉴于这会变得多么复杂,我对您的流程的猜测是直接 运行 流程。根本不要守护进程。
为了测试,(如果你在类 unix 环境中)你可以 运行 你的进程在后台:
./webserver start &
这将在后台生成新进程,但将其附加到您的 shell 进程列表中。这对于测试来说可能很好,因为如果 shell 消失,系统将一起清理这些附加的进程。
以上将把 stderr 和 stdout 文件描述符引导回您的终端并打印它们。如果你想避免这种情况,你总是可以 redirect 在其他地方输出。
像这样禁用信号给进程对我来说似乎不是正确的方法。一旦您需要保存状态或向客户端发送终止消息,请保存这些信号以优雅地退出您的流程。如果您执行上述操作,您的守护程序将只能通过 kill -9 <pid>
或重新启动,或找到一些您没有覆盖的非标准信号,其默认行为是终止。
这就是我想要实现的
root> ./webserver start // Does not block the terminal after startup, runs in the background and the process is guarded
root>
我目前的实现逻辑:
后台逻辑 运行ning use std::process::Command;
use std::thread;
use std::env;
use std::time::Duration;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() == 2 {
if &args[1] == "start" {
// Main process start child process
let child = Command::new(&args[0])
.spawn().expect("Child process failed to start.");
println!("child pid: {}", child.id());
// Main process exit
}
} else {Is there any more elegant approach? Looking forward to your reply
// Main business logic
run webserver
}
}
这样rust会在后台运行不阻塞终端,但是rust在后台打印的信息仍然会显示在终端上,退出时会退出当前的rust程序航站楼
进程守护逻辑我的想法是监听系统的退出信号,不处理退出请求
SIGHUP 1 /* Hangup (POSIX). */
SIGINT 2 /* Interrupt (ANSI). */
SIGQUIT 3 /* Quit (POSIX). */
SIGTERM 15 /* Termination (ANSI). */
代码:
use signal_hook::{iterator::Signals, SIGHUP,SIGINT,SIGQUIT,SIGTERM};
use std::{thread, time::Duration};
pub fn process_daemon() {
let signals = match Signals::new(&[SIGHUP,SIGINT,SIGQUIT,SIGTERM]) {
Ok(t) => t,
Err(e) => panic!(e),
};Is there any more elegant approach? Looking forward to your reply
thread::spawn(move || {
for sig in signals.forever() {
println!("Received signal {:?}", sig);
}
});
thread::sleep(Duration::from_secs(2));
}
有没有更优雅的做法?期待您的回复。
TLDR:如果您真的希望您的进程像服务一样运行(并且从不退出),可能需要设置一个服务管理器。否则,就让它成为一个正常的过程。
守护进程
立即注意到的一件事是 大多数 关于守护进程的考虑与 Rust 作为一种语言无关,更多的是关于:
- 您的进程所针对的底层系统
- 您的守护进程在生成后的确切行为
看了你的问题,你似乎已经意识到了大部分。不幸的是,为了正确回答您的问题,我们必须深入研究流程的复杂性及其管理方式。应该注意的是,如果您可以在启动基础架构中使用重要的平台 依赖性 ,那么现有的 'service' 管理器是一个很好的解决方案。
正如您所看到的,如果您想要一个可以正常工作的简单部署(前提是它是为相关系统编译的),这绝非易事。这些只是裸机服务管理器。如果你想支持虚拟环境,你将不得不考虑 Kubernetes 服务、dockerizing 等。
存在这些工具是因为在系统上管理长 运行ning 进程有很多考虑因素:
- 我的守护进程是否应该像服务一样运行并在被杀死(或系统重新启动)时重生?上面的工具将允许这样做。
- 如果是一项服务,我的守护程序是否应该具有与其关联的状态以帮助维护?这有助于管理中断和构建工具以横向扩展。
- 如果守护进程不应该是一个服务(在你的情况下不太可能给出你的二进制文件的名称)还有更多的问题:它应该附加到父进程吗?是否应该附加到登录进程组?
鉴于这会变得多么复杂,我对您的流程的猜测是直接 运行 流程。根本不要守护进程。
为了测试,(如果你在类 unix 环境中)你可以 运行 你的进程在后台:
./webserver start &
这将在后台生成新进程,但将其附加到您的 shell 进程列表中。这对于测试来说可能很好,因为如果 shell 消失,系统将一起清理这些附加的进程。
以上将把 stderr 和 stdout 文件描述符引导回您的终端并打印它们。如果你想避免这种情况,你总是可以 redirect 在其他地方输出。
像这样禁用信号给进程对我来说似乎不是正确的方法。一旦您需要保存状态或向客户端发送终止消息,请保存这些信号以优雅地退出您的流程。如果您执行上述操作,您的守护程序将只能通过 kill -9 <pid>
或重新启动,或找到一些您没有覆盖的非标准信号,其默认行为是终止。