我使用systemd用户计时器作为cron的替代。我有一个特定的程序设置为每20分钟执行一次。该程序不是守护进程,依赖于网络,并启动许多子进程。不过,我注意到计时器经常在几个小时(或几天)后停止。计时器仍处于活动状态,但程序不再每20分钟执行一次。pgrep
显示仍处于活动状态的多个进程。观察到这一点后,我将JobTimeoutSec=3m
添加到.service文件中,期望如果进程超时,它们将被终止。systemctl status --user PROGRAM.service
现在输出以下内容,但子进程仍在运行,计时器不再每隔20分钟执行一次程序:
2月13日15:03:45主机名systemd[1878]:job program.service/start超时。
2月13日15:03:45 hostname systemd[1878]:启动说明超时。
2月13日15:03:45主机名systemd[1878]:job program.service/start失败,结果为“timeout”。
我猜程序的子进程由于网络问题而暂停,systemd无法在超时时终止它们。
有什么建议可以解决这个问题,使计时器按预期继续工作吗?
用ExecStart=/path/to/program
替换ExecStart=/usr/bin/timeout 20m /path/to/program
似乎可以解决这个问题,但我想知道为什么仅systemd不能解决这个问题。
调试信息
程序服务
[Unit]
Description=DESCRIPTION
After=network.target
PartOf=network-online.target
JobTimeoutSec=3m
[Service]
Type=oneshot
ExecStart=/path/to/program
[Install]
WantedBy=network-online.target
程序计时器
[Unit]
Description=Run PROGRAM.service every 20 minutes
[Timer]
OnCalendar=*:0/20
[Install]
WantedBy=timers.target
systemd --version
输出以下内容:系统D 219
+pAM+审计+SELIXU+IMA+EMAPMOR+SyC+SysViT+UTMP+LBCuftStuts+GCRIPPT-GNUTLS+ACL+XZ-LZ4-SECCOMP+BLIDHE-EFUTILLS+KMOD-IDN
最佳答案
主动过程systemd
中有两件重要的事情,我认为您在本例中会用到:
使用systemd
启动进程时,所有子进程(至少在默认情况下)都是同一组的一部分。
如果这些孩子中的任何一个没有死,则认为进程仍在(至少在一定程度上)运行。
那是什么意思?
timer description表示:
请注意,如果要激活的单元在计时器结束时已处于活动状态,则它不会重新启动,而只是保持运行。
换句话说,如果您的任何进程在20分钟后仍在运行,计时器系统将不会重新启动任何进程。
为什么这有意义?啊!
克朗也在做同样的事。如果进程仍在运行,它不会一次又一次地重新启动它(因为这只会填满内存,可能会破坏许多其他东西)。所以如果你的主进程确实死了,它假设它可以重启它。
什么是系统解决方案?
假设您不能仅仅停止子进程(尽管由于使用了/usr/bin/timedout
,您可能可以?),一种方法是使用KillMode
选项,尽管我不建议这样做:
KillMode=process
这意味着一旦主进程终止,就认为服务已停止。
如果设置为process,则仅终止主进程本身。
你可能想测试这是否真的有效,因为根据文档,它没有说它会认为整个团队都死了…但根据我的经验,这是可行的。
那么,什么是更好的解决方案呢?
因为我不建议使用
KillMode
,所以应该有另一种解决方案。事实上,您的所有进程要么有20分钟的时间运行(或者在它们生成时还有多少时间),要么它们将阻止接下来的运行发生,这可能偶尔是可以的,但如果它们永远存在的话肯定不行。因此,应该编辑这些进程,并确保它们在一段时间后退出。但是,在很长一段时间之后,可能需要终止这些进程,如果进程本身不能按时退出,那么像您所做的那样使用超时工具可能是最好的解决方案。尽管我建议做一个小的修改,那就是超时使用19分钟,否则你可能会错过下一个启动窗口。
ExecStart=/usr/bin/timeout 19m /path/to/program
关于linux - 什么使我的systemd用户计时器停滞不前?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35387345/