【问题标题】:How to stop supervisor process with piped command如何使用管道命令停止主管进程
【发布时间】:2021-11-01 06:10:44
【问题描述】:

我想将服务器日志发送到电报机器人。这是我的主管配置:

[program:telegram-log-nginx]
process_name=%(program_name)s_%(process_num)02d
command=bash -c 'tail -f /var/log/nginx/error.log | /usr/share/telegram_log.sh nginx'
autostart=true
autorestart=true
numprocs=1

当我停止主管时

supervisorctl stop telegram-log-nginx:*

进程仍在运行:

ps aux | grep telegram
www-data 32151  0.0  0.0  21608  3804 ?        S    20:53   0:00 /bin/bash /usr/share/telegram_log.sh nginx

是否有适当的方法来停止所有进程?

telegram_log.sh

#!/bin/bash
CHATID="chat"
KEY="key"

SERVICE=$1

TIME="10"
URL="https://api.telegram.org/bot$KEY/sendMessage"

while IFS= read -r line; do
  read -r -d '' TEXT <<- EOM
  Service: $SERVICE
  $line
EOM
  curl -s --max-time $TIME -d "chat_id=$CHATID&disable_web_page_preview=1&text=$TEXT" $URL >/dev/null
done

├─supervisord,1101 /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf
  │   ├─php,643187 /var/www/web/artisan queue:work
  │   ├─php,643188 /var/www/web/artisan queue:work
  │   ├─php,643189 /var/www/web/artisan queue:work
  ├─systemd,640839 --user
  │   └─(sd-pam),640841
  ├─systemd-journal,406
  ├─systemd-logind,1102
  ├─systemd-resolve,807
  ├─systemd-timesyn,684
  │   └─{systemd-timesyn},689
  ├─systemd-udevd,440
  ├─tail,643203 -f /var/log/nginx/error.log
  ├─telegram_log.sh,643204 /usr/share/telegram_log.sh nginx

【问题讨论】:

  • supervisord 是否让您像 systemd 那样杀死整个进程的 cgroup?如果是这样,这就是我要开始的地方。
  • @CharlesDuffy 我试过 stopasgroup=true,没用
  • 有趣。我真的很想让了解主管的人跳到这里——我非常了解 bash,并且必须使用 systemd,但我更喜欢的 init 系统是 daemontools 套件;我根本不认识主管。
  • 也就是说...如果您启用了nullglob 选项,则telegram-log-nginx:* 可以在supervisorctl 看到它之前由shell 从参数列表中删除,从而使命令只是@987654328 @。引用可能被解释为 glob 的参数总是更安全; supervisorctl stop 'telegram-log-nginx:*'.
  • 顺便说一句,如果您想让信号直接进入执行telegram_log.sh 的shell,而不是设置管道的那个,我会考虑类似bash -c 'exec &lt; &lt;(exec tail -f /var/log/nginx/error.log); exec /usr/share/telegram_log.sh nginx' 的东西。 (这意味着它不会转到tail 的副本,但tail 在尝试写入标准输出并获得SIGPIPE 时会退出)。

标签: linux bash supervisord


【解决方案1】:

假设您有一个足够新的 bash 版本来处理替换更新 $!,您可以让您的父脚本存储其直接子代的 PID 并在关闭期间显式地发出信号:

#!/usr/bin/env bash

# make our stdin come directly from tail -f; record its PID
exec < <(exec tail -f /var/log/nginx/error.log); tail_pid=$!

# start telegram_log.sh in the background inheriting our stdin; record its PID
/usr/share/telegram_log.sh nginx & telegram_script_pid=$!

# close our stdin to ensure that we don't keep the tail alive -- only
# telegram_log.sh should have a handle on it
exec </dev/null

# define a cleanup function that shuts down both subprocesses
cleanup() { kill "$tail_pid" "$telegram_script_pid"; }

# tell the shell to call the cleanup function when receiving a SIGTERM, or exiting
trap cleanup TERM EXIT

# wait until telegram_log.sh exits and exit with the same status
wait "$telegram_script_pid"

这意味着您的配置文件可能会变得更像:

command=bash -c 'exec < <(exec tail -f /var/log/nginx/error.log); tail_pid=$!; /usr/share/telegram_log.sh nginx & telegram_script_pid=$!; exec </dev/null; cleanup() { kill "$tail_pid" "$telegram_script_pid"; }; trap cleanup TERM EXIT; wait "$telegram_script_pid"'

【讨论】:

  • 在生产服务器上尝试了您的解决方案,它有效。谢谢!
【解决方案2】:

@CharlesDuffy 提供了答案

bash -c 'tail -f /var/log/nginx/error.log | /usr/share/telegram_log.sh nginx'

应该是

bash -c 'exec < <(exec tail -f /var/log/nginx/error.log); exec /usr/share/telegram_log.sh nginx'

【讨论】:

  • 等一下,前面的建议有效吗?你知道你之前试过为什么会失败吗?
猜你喜欢
  • 1970-01-01
  • 2012-09-25
  • 1970-01-01
  • 1970-01-01
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 1970-01-01
相关资源
最近更新 更多