今天是周五,我想分享一些我今天学到的东西。和许多事情一样,文档是存在的,但需要一点技巧才能将它们整合起来。希望这能帮助未来在搜索问题答案时遇到同样情况的人。
我们希望用 Rust 编写的 netavark-dhcp-proxy 应用程序能够以两种模式运行:手动模式和由 systemd 套接字激活的模式。手动模式就是作为一个命令行应用程序简单运行。systemd 套接字激活模式基本上就是 systemd “拥有”套接字,当有人尝试使用该套接字时,它将启动服务。套接字激活是一种很好的方法,可以使不经常运行的服务按需可用。如果你为服务内置了非活动超时,它可以在满足你想要的任何条件后自行关闭。
关于 systemd 的套接字激活服务,需要注意一点是,当服务启动时,它不会直接监听特定的套接字文件,而是会监听文件描述符 (FD) 3。
“…作为基于套接字激活逻辑的一部分。它返回接收到的文件描述符的数量。如果没有收到文件描述符,则返回零。第一个文件描述符可以在文件描述符编号 3 中找到…”
sd_listen_fds(3)
要确定你的服务是否由 systemd 激活,你需要检查环境变量键 LISTEN_FDS 是否存在。这是代理代码中 Rust 的实际示例,我们在这里查找环境变量,如果找到,我们从 FD 3 创建一个 UnixListener。
let uds: UnixListener = match env::var("LISTEN_FDS") {
Ok(effds) => {
if effds != "1" {
error!("Received more than one FD from systemd");
return Ok(());
}
let systemd_socket = unsafe { stdUnixListener::from_raw_fd(3) };
UnixListener::from_std(systemd_socket)?
}
// Use the standard socket approach
Err(..) => UnixListener::bind(&uds_path)?,
};
let uds_stream = UnixListenerStream::new(uds);
然而,在测试时,我注意到退出应用程序的非活动超时没有触发。我获取了应用程序的 PID,strace 显示它正在等待一个 accept。
$ sudo strace -p 479503 strace: Process 479503 attached accept4(3,
我感到困惑。显然,问题出在代理如何处理套接字上,但我无法确定具体问题。然后我的队友 @pholzing 指出 UnixListener::from_std 需要一个非阻塞的 FD,而这并不是 from_raw 的默认设置。我们只需要将从原始文件描述符打开的套接字更改为非阻塞模式。
let systemd_socket = unsafe { stdUnixListener::from_raw_fd(3) }; systemd_socket.set_nonblocking(true)?;
搞定了!问题解决了。完整的代码可以在我的 systemd 套接字激活拉取请求中看到。我希望这能在将来帮助那些面临类似挑战的人。
发表评论