我在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服务只会增加麻烦。)
答案 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并终止该服务。