使用boost::process来完全分离进程



我有一个systemd服务,它运行并完成它的任务。我需要它定期自我升级,这需要关闭和重新启动服务。出于疑问,升级脚本可以简单到:

echo "Stopping service..."
systemctl stop myservice
echo "Doing some stuff..."
sleep 10s
echo "Starting service..."
systemctl start myservice

我想在服务本身中调用它,最好使用boost::process:

boost::process::child instexe{
boost::process::search_path("bash"), 
std::vector<std::string>{"installerscript.sh"},
boost::process::start_dir("/installer/folder"),
boost::process::std_out > "/some/log/file.txt"
};
instexe.detach();

问题是,一旦脚本调用systemctl stop myservice,安装程序脚本就会被终止。

有没有一种方法可以让我用boost::process做我想做的事情?或者我该怎么做?

如果升级处于预定义的时间段,您可以考虑使用crontab。https://opensource.com/article/17/11/how-use-cron-linux

00 09-17 * * 1-5 /usr/local/bin/installerScript.sh

crontab中的上述条目将使程序在周一至周五上午9点至下午5点之间每小时升级一次。您可以考虑和配置许多组合。

有没有一种方法可以用boost::process做我想做的事情?或者我该怎么做?

如果您让子进程杀死父进程,那么根据定义,总会有一个竞赛条件。

快速破解是在安装程序脚本的开头放一个sleep语句,但正确的解决方案是显式地与子级同步:

  1. 让安装程序脚本检测它是否以交互方式运行(即,从终端手动运行,而不是由您的服务运行(
  2. 如果它是非交互式的(您的用例(,让它等待stdin中的一些输入
  3. 创建子项时连接stdin管道
  4. 分离孩子并,然后写一些东西告诉孩子它是安全的

其他同步机制也可用,你可以使用锁定文件或信号-你只需要确保孩子在父母分离它之前不会做任何事情。

我发现(从这个问题中,得出了优秀但不可理解的systemd.kill手册页(systemd有四种不同的停止装置的方法,由装置配置中的KillMode变量控制:

  • control-group将向单元的cgroup中的每个进程发送SIGTERM(默认情况下,可使用KillSignal重写(。这意味着父母和孩子
  • mixed会将SIGTERM(或KillSignal(发送到您的主进程,并将SIGKILL发送到子进程
  • process只会杀死主进程,而不理孩子
  • 不建议使用none,它只会运行您的ExecStop过程

您可能只需设置KillMode=process,但请注意,如果SendSIGKillSendSIGUP为真,则在TimeoutStopSec之后,这些信号仍将传递给您的孩子。

重新启动服务并有一个启动脚本可以在启动时对其进行更新,或者在ExecStop过程中执行更新,似乎比说服systemd在更新完成之前不要管孩子更简单,没有挂起的孩子更新程序永远挂起的风险。

无论哪种方式,您剩下的问题都只与systemd有关,而不是与boost.Process有关。

最新更新