哑初始化

哑初始化

我有一个临时案例,作为用户,我希望启动一些服务进程,并且能够将它们全部中断,以实现干净、轻松的启动停止。 “docker-compose up”的行为接近我想要的,所有 stdout/stderr feed 都到​​达我调用 shell 的 stdout/stderr,并且 sigint 一起关闭所有进程。

我尝试过supervisord和circus,但是两者都有点过于以生产为中心,需要解决方法来加入标准流,留在前台,通常表现得不像前台进程。我确信有不错的工具可以做到这一点,我已经看到它是在普通的外壳中完成的,我宁愿避免这种情况,但如果样板不是太极端的话,它是一个选择。

这个结果出现在谷歌“霸主”上https://github.com/dpedu/overlord其中谈到了同样的目标和麻烦,但我在这里没有看到任何程序

对于通用语言,假设我想运行 foo、bar 和 baz,合并它们的 stdout/error,然后休眠直到出现 sigint,该 sigint 应该向这三个程序中的每一个程序发送 sigint,然后等待每个程序退出。再说一遍,如果我必须在 shell 中执行此操作,那很好,但我真的很想了解开发人员流程组合工具(除了 docker-compose、docker、init 或以容器为中心的工具之外)是否有专为此类任务构建的工具

额外的奖励功能是保留 tty 信息,以便子进程可以启用自动颜色,但没什么大不了的

#!/bin/sh
./foo &
./bar &
./baz &

在写这篇文章时,我遇到了

答案1

哑初始化

https://github.com/Yelp/dumb-init

  • 在 debian 中打包(apt install dump-init)

配置示例,创建“./start”并为其指定内容:

#!/usr/bin/dumb-init /bin/sh
./foo &  # launch a process in the background
./bar &
./baz  # launch another process in the foreground

不要忘记像平常一样使用 ^Cchmod +x ./start运行/退出./start

答案2

您也许可以使用一个systemd解决方案,其中foo.servicebar.servicebaz.service,全部由更大的事物启动super.service并由同一事物停止。

这样做的一些优点:

  • 您可以选择该组单元如何响应故障。
  • 您不必为此专门设置一个终端窗口(您可以关闭终端而不影响进程)
  • 可以保存日志记录,因此您可以使用工具来解析感兴趣的部分,而不是手动滚动终端。

它不会像您想要的那样将这些进程保留在前台,但除非这些进程是交互式进程,否则将它们保留在前台没有太大价值。

这是完成此操作的一组文件:

# ~/.config/systemd/user/super.service
[Unit]
Description=running everything

[Service]
Type=oneshot
ExecStart=/bin/true
RemainAfterExit=yes
--------------------------------------------
# ~/.config/systemd/user/foo.service
[Unit]
PartOf=super.service

[Service]
ExecStart=%h/bin/foo

[Install]
WantedBy=super.service
--------------------------------------------
# ~/.config/systemd/user/bar.service
[Unit]
PartOf=super.service

[Service]
ExecStart=%h/bin/bar

[Install]
WantedBy=super.service
--------------------------------------------
# ~/.config/systemd/user/baz.service
[Unit]
PartOf=super.service

[Service]
ExecStart=%h/bin/baz

[Install]
WantedBy=super.service

解释:

  • WantedBy=super.service意味着什么时候super.service开始,这也会开始。
  • PartOf=super.service意味着当super.service停止时,这也会停止。

控制:

  • 将每个单元添加到super组中systemctl --user enable foo bar baz
  • 启动所有进程systemctl --user start super
  • 停止所有进程systemctl --user stop super
  • 使用以下命令在同一窗口中查看所有进程的标准输出journalctl -u foo -u bar -u baz:添加-f以持续关注屏幕上的标准输出。

其他注意事项:

  • 添加KillSignal=SIGINT到仅优雅停止的任何服务SIGINT(否则他们会得到SIGTERM
  • 如果foo崩溃或无法启动,您可以强制其他进程停止。通过更改WantedBy=为来做到这一点RequiredBy=。如果无法启动,则会导致super.service停止,从而导致停止。foobarbaz
  • 您还可以添加BindsTo=关系以导致super.service停止,如果foo barbaz因任何原因停止(例如自然结束或失败)。
  • 使用的一个好处journalctl是它可以告诉您元数据,例如单元何时启动/停止以及哪个进程打印了消息。但是,如果您不喜欢此详细信息,请添加StandardOutput=append:%h/log到每个[Service]部分。这会将所有日志放入~/log.然后您就可以tail -f ~/log观看它。我认为这样做时颜色也可以得到更好的保留。

答案3

您提到您更喜欢避免使用 shell,但这正是 shell 的用途,不是吗?

在 bash 中,要启动许多后台进程,你只需这样做

./job1 & ./job2 & ./job3 &

向所有这些发送 INT 信号:

kill -INT $(jobs -p)

等待所有这些都完成:

wait

如果问题是您想要重复启动同一组作业,您可以设置

alias start="./job1 & ./job2 & ./job3 &"
alias stop='kill -INT $(jobs -p); wait'

然后,如果你想杀死他们,只需输入start即可将他们全部解雇。stop

相关内容