1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3use std::{
4 env,
5 os::unix::process::CommandExt,
6 process::{Command, Stdio},
7};
8
9use log::{error, info};
10use nix::unistd;
11use tokio::{
12 signal::unix::{SignalKind, signal},
13 task,
14};
15pub use tokio_util::sync::CancellationToken;
16
17pub fn listen() -> Result<CancellationToken, std::io::Error> {
19 let mut stream = signal(SignalKind::hangup())?;
20
21 let token = CancellationToken::new();
22 let token_for_task = token.clone();
23
24 task::spawn(async move {
25 stream.recv().await;
26 info!("接收到 SIGHUP 信号,开始重载进程");
27
28 let current_exe = match env::current_exe() {
29 Ok(path) => path,
30 Err(e) => {
31 error!("NO EXE PATH {}", e);
32 return;
33 }
34 };
35
36 let args: Vec<String> = env::args().collect();
38
39 info!("启动新的子进程: {} {:?}", current_exe.display(), &args[1..]);
40
41 let mut command = Command::new(current_exe);
42
43 unsafe {
44 command
45 .args(&args[1..])
46 .stdin(Stdio::null())
47 .stdout(Stdio::inherit())
48 .stderr(Stdio::inherit())
49 .pre_exec(|| {
50 unistd::setsid().map_err(std::io::Error::other)?;
52 Ok(())
53 });
54 }
55
56 match command.spawn() {
57 Ok(child) => {
58 info!("成功启动新的子进程,PID: {} ; 母进程开始关闭。", child.id());
59 token_for_task.cancel();
60 }
61 Err(e) => {
62 error!("启动新进程失败: {}", e);
63 }
64 }
65 });
66
67 Ok(token)
68}