而bash脚本中的循环会破坏systemd服务

时间:2017-03-31 02:35:08

标签: linux bash debian systemd

我在Debian上,我有一个调用bash脚本的systemd服务。

该脚本包含一个无限循环,因为我需要它每隔X秒无限地检查一次。

一旦遇到“while true; do”行,systemd服务就会崩溃。

如果我手动执行脚本,脚本运行正常。 为什么没有这样的系统?我该怎么办?

这是服务和脚本。正如我所指出的,在“while true; do”打印之前的回声。 “while true; do”行之后的echo语句不会打印。

/etc/systemd/system/stream.service:

[Service]
WorkingDirectory=/home/pi/
ExecStart=/home/pi/joi_main.sh
Restart=no
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=stream_service
User=pi
Group=pi
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.target

/home/pi/joi_main.sh:

#!/bin/bash -e

today=`/bin/date '+%Y_%m_%d__%H_%M_%S'`
exec 2> "/home/pi/stream_logs/$today.$RANDOM.log"
exec 1>&2

#Wait 120s for system to finish booting
sleep 120

#Initial config
export AUDIODEV=mic_mono
export AUDIODRIVER=alsa
sudo sysctl fs.pipe-max-size=1048576

echo "This line prints"

# Check if video buffer is full every minute. if full, the stream needs to restart
while true; do
    echo "This line doesn't"
    if grep "100% full" /home/pi/video_buffer_usage.txt; then
        echo "Buffer is full!"
    # Kill existing processes
        pkill -f “raspivid|rec|buffer|ffmpeg”
    # Wait 10s
         sleep 10
         ./joi_stream.sh &
    fi
    sleep 60
done

Journalctl看起来完全没有用,但现在就是这样。没有错误。为什么“会议结束”?

Mar 31 02:13:41 raspberrypi sudo[1369]: pi : TTY=unknown ; PWD=/home/pi ; USER=root ; COMMAND=/sbin/sysctl fs.pipe-max-size=1048576
Mar 31 02:13:41 raspberrypi sudo[1369]: pam_unix(sudo:session): session opened for user root by (uid=0)
Mar 31 02:13:41 raspberrypi sudo[1369]: pam_unix(sudo:session): session closed for user root

(请不要告诉我为这个while循环启动另一个systemd服务。我希望它成为这个主要脚本的一部分,因为它需要在其他所有内容之后运行,如果我关闭主服务我不希望while循环运行,因此维护两个systemd服务只会增加麻烦。)

2 个答案:

答案 0 :(得分:1)

./joi_stream.sh的内容未分享,但我在systemd解决方案中遇到了问题。它并没有直接解释你的行为,但可能是相关的:

systemd配置中,您将STDOUT和STDERR重定向到syslog,但在脚本中,您将STDERR(文件描述符" 2")重定向到文件,并且将STDOUT(文件描述符" 1')重定向到STDERR。

exec 2> "/home/pi/stream_logs/$today.$RANDOM.log"
exec 1>&2

如果您的./joi_stream.sh期望将这些文件描述符重定向到另一个文件,则可能不会。如果该文件仅用于记录,我将删除这些行并让systemd日志处理 - 它将使用您的单元标记日志,您可以专门查看日志:

 journalctl -u your-unit-name.service

此外,在systemd中,您通常无法进入睡眠状态,等待系统启动。相反,您将使用.timer单位。

.timer文件将指示每分钟运行主逻辑,因此"同时"不需要循环。计时器单元将包含如下指令:

#启动后2分钟第一次运行    #和之后的每一分钟    OnBootSec = 120    OnUnitActiveSec = 60

timer 单元,启用启动时启动。定时器文件可以非常简单。只需在.timer中创建一个/etc/systemd/system文件,并为其指定与您希望其激活的服务文件相同的名称:

[Unit]
Description=Runs my service every minute

[Timer]
# Run for the first time 2 minutes after boot 
# and every minute after that
OnBootSec=120 
OnUnitActiveSec=60

[Install]
WantedBy=timers.target

要立即开始并测试您的计时器,请运行:

sudo systemctl start my-service.timer

您可以使用以下方式查看计时器的状态:

sudo systemctl list-timers

systemd解决方案比rc.local解决方案更强大。如果您的rc.local解决方案因任何原因而死亡,则不会重新启动。但是,如果您的脚本将在systemd下运行,则计时器仍会在一分钟后再次运行。

答案 1 :(得分:0)

仅供参考,如果我从/etc/rc.local调用/home/pi/joi_main.sh而不是使用systemd服务,一切正常。我将使用rc.local并终止该服务。