业务爸爸的需求
需求:有个跑批任务 /data/wwwroot/cmd/OnlyOnceController.php,需要开通 n(>=3)个进程同时处理, 同时满足如下条件:
把日志重向到对应的日志文件如(out_[N].log, N 对应进程编号)
如果任务异常退出,并能拉起。(注意如果进程 3 拉起后,日志还要继续追加到之前的 out_3.log)
为了方便演示,我把有业务逻辑的php 程序,换成一个shell脚本,如下:
root@VM-ubuntu:/opt/tmp# cat tpl.sh
while true; do
echo "$(date +'%Y-%m-%d %H:%M:%S')"
sleep 10s
done
执行任务命令: nohup bash tpl.sh >> out_1.log &
复制代码
无脑脚本大法
思路如下: 由于重定向是在程序执行时进行的操作,ps 命令无法直接查看程序的重定向信息。所以为了满足上面要求的第二条,我们需要把脚本名设置成唯一的。如 tpl_1.sh.
# cat run.sh
#!/bin/bash
# author 小毛驴
#
SHELL_DIR=$(cd $(dirname $0);pwd)
cd ${SHELL_DIR}
# 任务数量
NUM_TASKS=3
# 任务命令
TASK_CMD_TPL="tpl.sh"
# 循环监控脚本的运行状态
while true; do
for ((i=1; i<=$NUM_TASKS; i++)); do
# 检查任务是否已经在运行
echo ${TASK_CMD_TPL}
if ! pgrep -f "${TASK_CMD_TPL}_$i" > /dev/null; then
if [ ! -e ${TASK_CMD_TPL}_$i ]; then
cp ${TASK_CMD_TPL} ${TASK_CMD_TPL}_$i
chmod +x ${TASK_CMD_TPL}_$i
fi
nohup bash ${TASK_CMD_TPL}_$i >> out_$i.log &
echo "Task ${TASK_CMD_TPL}_$i started."
else
echo "Task ${TASK_CMD_TPL}_$i is already running."
fi
done
sleep 10
done
复制代码
# ls
nohup.out out_1.log out_2.log out_3.log run.sh tpl.sh tpl.sh_1 tpl.sh_2 tpl.sh_3
# pgrep -f tpl.sh
15855
16043
16100
# tail -f out*.log
==> out_1.log <==
2023-04-10 22:49:12
==> out_2.log <==
2023-04-10 22:49:12
==> out_3.log <==
2023-04-10 22:49:12
复制代码
虽然比较 low,但是功能也实现。注意为了防止 run.sh 意外退出,上面的 run.sh 脚本要放到 crontab 任务并加一个排它锁,或者称为写入锁。
有没有更好的方式呢?
那肯定是有的,我们之所以用 tpl.sh_1 tpl.sh_2 这些脚本,就是执行运行多个 tpl.sh 脚本后,如果其中一个挂掉,重新拉起,不能满足上述要求的第二条。如果每个脚本或者命令执行的时候都有一个唯一 id,基于这个 id 拉起对应的任务,那就解决要复制多个脚本的问题了。
给命令加一个唯一 id
command --unique-id xxxx 的方式,给每个脚本或者命令执行的时候指定一个唯一id。
复制代码
# cat unique-id.sh
#!/bin/bash
# author 小毛驴
#
SHELL_DIR=$(cd $(dirname $0);pwd)
cd ${SHELL_DIR}
# 任务数量
NUM_TASKS=3
# 任务命令
TASK_CMD_TPL="tpl.sh"
# 循环监控脚本的运行状态
while true; do
for ((i=1; i<=$NUM_TASKS; i++)); do
# 检查任务是否已经在运行
# 此时检查的是 唯一id
if ! pgrep -f "${TASK_CMD_TPL}_$i" > /dev/null; then
nohup bash ${TASK_CMD_TPL} --unique-id "${TASK_CMD_TPL}_$i" >> out_$i.log &
echo "Task ${TASK_CMD_TPL}_$i started."
else
echo "Task ${TASK_CMD_TPL}_$i is already running."
fi
done
sleep 10
done
复制代码
# nohup bash unique-id.sh &
# ps -ef | grep tpl.sh
root 22689 22675 0 23:03 pts/1 00:00:00 bash tpl.sh --unique-id tpl.sh_1
root 22693 22675 0 23:03 pts/1 00:00:00 bash tpl.sh --unique-id tpl.sh_2
root 22697 22675 0 23:03 pts/1 00:00:00 bash tpl.sh --unique-id tpl.sh_3
# tail -f out*.log
==> out_1.log <==
2023-04-10 23:03:32
==> out_2.log <==
2023-04-10 23:03:32
==> out_3.log <==
2023-04-10 23:03:32
复制代码
交给专业工具
专业的工具做专业的事情,比如 supervisor
复制代码
root@VM-ubuntu:/etc/supervisor/conf.d# cat tpl.conf
[program:tpl]
process_name=%(program_name)s_%(process_num)02d
command=bash /opt/tmp/tpl.sh
stderr_logfile=/opt/tmp/%(program_name)s_%(process_num)02d_err.log
stdout_logfile=/opt/tmp/%(program_name)s_%(process_num)02d_out.log
autostart=true
user=root
autorestart=true
startretries=100
startsecs=10
numprocs=3
复制代码
root@VM-ubuntu:/etc/supervisor/conf.d# supervisorctl
supervisor> update
tpl: added process group
supervisor> status
tpl:tpl_00 RUNNING pid 27674, uptime 0:00:11
tpl:tpl_01 RUNNING pid 27671, uptime 0:00:11
tpl:tpl_02 RUNNING pid 27675, uptime 0:00:11
复制代码
root@VM-ubuntu:/etc/supervisor/conf.d# pgrep -f tpl.sh
27671
27674
27675
root@VM-ubuntu:/etc/supervisor/conf.d# ps -ef | grep tpl.sh | grep -v "grep"
root 27671 1410 0 23:14 ? 00:00:00 bash /opt/tmp/tpl.sh
root 27674 1410 0 23:14 ? 00:00:00 bash /opt/tmp/tpl.sh
root 27675 1410 0 23:14 ? 00:00:00 bash /opt/tmp/tpl.sh
# tail -f tpl_0*
==> tpl_00_err.log <==
==> tpl_00_out.log <==
2023-04-10 23:15:24
2023-04-10 23:15:34
2023-04-10 23:15:44
2023-04-10 23:15:54
==> tpl_01_err.log <==
==> tpl_01_out.log <==
2023-04-10 23:15:24
2023-04-10 23:15:34
2023-04-10 23:15:44
2023-04-10 23:15:54
==> tpl_02_err.log <==
==> tpl_02_out.log <==
2023-04-10 23:15:24
2023-04-10 23:15:34
2023-04-10 23:15:44
2023-04-10 23:15:54
复制代码
评论