如何让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 作为一种语言无关,更多的是关于:

  1. 您的进程所针对的底层系统
  2. 您的守护进程在生成后的确切行为

看了你的问题,你似乎已经意识到了大部分。不幸的是,为了正确回答您的问题,我们必须深入研究流程的复杂性及其管理方式。应该注意的是,如果您可以在启动基础架构中使用重要的平台 依赖性 ,那么现有的 'service' 管理器是一个很好的解决方案。

正如您所看到的,如果您想要一个可以正常工作的简单部署(前提是它是为相关系统编译的),这绝非易事。这些只是裸机服务管理器。如果你想支持虚拟环境,你将不得不考虑 Kubernetes 服务、dockerizing 等。

存在这些工具是因为在系统上管理长 运行ning 进程有很多考虑因素:

  • 我的守护进程是否应该像服务一样运行并在被杀死(或系统重新启动)时重生?上面的工具将允许这样做。
  • 如果是一项服务,我的守护程序是否应该具有与其关联的状态以帮助维护?这有助于管理中断和构建工具以横向扩展。
  • 如果守护进程不应该是一个服务(在你的情况下不太可能给出你的二进制文件的名称)还有更多的问题:它应该附加到父进程吗?是否应该附加到登录进程组?

鉴于这会变得多么复杂,我对您的流程的猜测是直接 运行 流程。根本不要守护进程。

为了测试,(如果你在类 unix 环境中)你可以 运行 你的进程在后台:

./webserver start &

这将在后台生成新进程,但将其附加到您的 shell 进程列表中。这对于测试来说可能很好,因为如果 shell 消失,系统将一起清理这些附加的进程。

以上将把 stderr 和 stdout 文件描述符引导回您的终端并打印它们。如果你想避免这种情况,你总是可以 redirect 在其他地方输出。

像这样禁用信号给进程对我来说似乎不是正确的方法。一旦您需要保存状态或向客户端发送终止消息,请保存这些信号以优雅地退出您的流程。如果您执行上述操作,您的守护程序将只能通过 kill -9 <pid> 或重新启动,或找到一些您没有覆盖的非标准信号,其默认行为是终止。