[转帖]在 Linux 上使用 systemd 设置定时器
在 Linux 上使用 systemd 设置定时器
https://linux.cn/article-10182-1.html
| 2018-11-01 22:13 收藏: 1 分享: 3
学习使用 systemd 创建启动你的游戏服务器的定时器。
之前,我们看到了如何手动的、在开机与关机时、在启用某个设备时、在文件系统发生改变时 启用与禁用 systemd 服务。
定时器增加了另一种启动服务的方式,基于……时间。尽管与定时任务很相似,但 systemd 定时器稍微地灵活一些。让我们看看它是怎么工作的。
“定时运行”
让我们展开本系列前两篇文章中你所设置的 Minetest 服务器作为如何使用定时器单元的第一个例子。如果你还没有读过那几篇文章,可以现在去看看。
你将通过创建一个定时器来“改进” Minetest 服务器,使得在服务器启动 1 分钟后运行游戏服务器而不是立即运行。这样做的原因可能是,在启动之前可能会用到其他的服务,例如发邮件给其他玩家告诉他们游戏已经准备就绪,你要确保其他的服务(例如网络)在开始前完全启动并运行。
最终,你的 minetest.timer
单元看起来就像这样:
<span>#<span> minetest<span>.<span>timer</span></span></span></span>
<span>[<span>Unit<span>]</span></span></span>
<span>Description<span>=<span>Runs<span> the minetest<span>.<span>service <span>1<span> minute after boot up</span></span></span></span></span></span></span></span>
<span>[<span>Timer<span>]</span></span></span>
<span>OnBootSec<span>=<span>1<span> m</span></span></span></span>
<span>Unit<span>=<span>minetest<span>.<span>service</span></span></span></span></span>
<span>[<span>Install<span>]</span></span></span>
<span>WantedBy<span>=<span>basic<span>.<span>target</span></span></span></span></span>
一点也不难吧。
如以往一般,开头是 [Unit]
和一段描述单元作用的信息,这儿没什么新东西。[Timer]
这一节是新出现的,但它的作用不言自明:它包含了何时启动服务,启动哪个服务的信息。在这个例子当中,OnBootSec
是告诉 systemd 在系统启动后运行服务的指令。
其他的指令有:
OnActiveSec=
,告诉 systemd 在定时器启动后多长时间运行服务。OnStartupSec=
,同样的,它告诉 systemd 在 systemd 进程启动后多长时间运行服务。OnUnitActiveSec=
,告诉 systemd 在上次由定时器激活的服务启动后多长时间运行服务。OnUnitInactiveSec=
,告诉 systemd 在上次由定时器激活的服务停用后多长时间运行服务。
继续 minetest.timer
单元,basic.target
通常用作后期引导服务late boot services的同步点synchronization point。这就意味着它可以让 minetest.timer
单元运行在安装完本地挂载点local mount points或交换设备,套接字、定时器、路径单元和其他基本的初始化进程之后。就像在第二篇文章中 systemd 单元里解释的那样,targets
就像旧的运行等级old run levels一样,可以将你的计算机置于某个状态,或像这样告诉你的服务在达到某个状态后开始运行。
在前两篇文章中你配置的 minetest.service
文件最终看起来就像这样:
<span>#<span> minetest<span>.<span>service</span></span></span></span>
<span>[<span>Unit<span>]</span></span></span>
<span>Description<span>=<span> <span>Minetest<span> server</span></span></span></span></span>
<span>Documentation<span>=<span> https<span>:<span>//wiki.minetest.net/Main_Page</span></span></span></span></span>
<span>[<span>Service<span>]</span></span></span>
<span>Type<span>=<span> simple</span></span></span>
<span>User<span>=</span></span>
<span>ExecStart<span>=<span> <span>/usr/<span>games<span>/<span>minetest <span>--<span>server</span></span></span></span></span></span></span></span></span>
<span>ExecStartPost<span>=<span> <span>/home/<span>/<span>bin<span>/<span>mtsendmail<span>.<span>sh <span>"Ready to rumble?"<span> <span>"Minetest Starting up"</span></span></span></span></span></span></span></span></span></span></span></span></span>
<span>TimeoutStopSec<span>=<span> <span>180</span></span></span></span>
<span>ExecStop<span>=<span> <span>/home/<span>/<span>bin<span>/<span>mtsendmail<span>.<span>sh <span>"Off to bed. Nightie night!"<span> <span>"Minetest Stopping in 2 minutes"</span></span></span></span></span></span></span></span></span></span></span></span></span>
<span>ExecStop<span>=<span> <span>/bin/<span>sleep<span> <span>120</span></span></span></span></span></span></span>
<span>ExecStop<span>=<span> <span>/bin/<span>kill<span> <span>-<span>2<span> $MAINPID</span></span></span></span></span></span></span></span></span>
<span>[<span>Install<span>]</span></span></span>
<span>WantedBy<span>=<span> multi<span>-<span>user<span>.<span>target</span></span></span></span></span></span></span>
这儿没什么需要修改的。但是你需要将 mtsendmail.sh
(发送你的 email 的脚本)从:
<span>#<span>!<span>/bin/<span>bash</span></span></span></span>
<span>#<span> mtsendmail</span></span>
<span>sleep<span> <span>20</span></span></span>
<span>echo<span> $1 <span>|<span> mutt <span>-<span>F <span>/<span>home<span>/<<span>username<span>>/.<span>muttrc <span>-<span>s <span>"$2"<span> _list<span>.<span>com</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
<span>sleep<span> <span>10</span></span></span>
改成:
<span>#<span>!<span>/bin/<span>bash</span></span></span></span>
<span>#<span> mtsendmail<span>.<span>sh</span></span></span></span>
<span>echo<span> $1 <span>|<span> mutt <span>-<span>F <span>/<span>home<span>/<span>paul<span>/.<span>muttrc <span>-<span>s <span>"$2"<span> <span>.<span>com</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
你做的事是去除掉 Bash 脚本中那些蹩脚的停顿。Systemd 现在来做等待。
让它运行起来
确保一切运作正常,禁用 minetest.service
:
<span>sudo<span> <span>systemctl<span> disable minetest</span></span></span></span>
这使得系统启动时它不会一同启动;然后,相反地,启用 minetest.timer
:
<span>sudo<span> <span>systemctl<span> enable minetest<span>.<span>timer</span></span></span></span></span></span>
现在你就可以重启服务器了,当运行 sudo journalctl -u minetest.*
后,你就会看到 minetest.timer
单元执行后大约一分钟,minetest.service
单元开始运行。
图 1:minetest.timer 运行大约 1 分钟后 minetest.service 开始运行
时间的问题
minetest.timer
在 systemd 的日志里显示的启动时间为 09:08:33 而 minetest.service
启动时间是 09:09:18,它们之间少于 1 分钟,关于这件事有几点需要说明一下:首先,请记住我们说过 OnBootSec=
指令是从引导完成后开始计算服务启动的时间。当 minetest.timer
的时间到来时,引导已经在几秒之前完成了。
另一件事情是 systemd 给自己设置了一个误差幅度margin of error(默认是 1 分钟)来运行东西。这有助于在多个资源密集型进程resource-intensive processes同时运行时分配负载:通过分配 1 分钟的时间,systemd 可以等待某些进程关闭。这也意味着 minetest.service
会在引导完成后的 1~2 分钟之间启动。但精确的时间谁也不知道。
顺便一提,你可以用 AccuracySec=
指令修改误差幅度。
你也可以检查系统上所有的定时器何时运行或是上次运行的时间:
<span>systemctl<span> <span>list<span>-<span>timers <span>--<span>all</span></span></span></span></span></span></span>
图 2:检查定时器何时运行或上次运行的时间
最后一件值得思考的事就是你应该用怎样的格式去表示一段时间。Systemd 在这方面非常灵活:2 h
,2 hours
或 2hr
都可以用来表示 2 个小时。对于“秒”,你可以用 seconds
,second
,sec
和 s
。“分”也是同样的方式:minutes
,minute
,min
和 m
。你可以检查 man systemd.time
来查看 systemd 能够理解的所有时间单元。
下一次
下次你会看到如何使用日历中的日期和时间来定期运行服务,以及如何通过组合定时器与设备单元在插入某些硬件时运行服务。
回头见!
在 Linux 基金会和 edx 上通过免费课程 “Introduction to Linux” 学习更多关于 Linux 的知识。