继续systemd教程,这些具体示例将向您展示如何更好地使用systemd定时器单元。在这个systemd教程系列中,我们在一定程度上讨论了systemd定时器单元。然而,在我们开始讨论套接字之前,让我们看一下三个示例,它们展示了如何充分利用这些单元。简单的类似cron的行为我每周都会收集Debianpopcon数据,如果每次都可以同时完成就好了,这样我就可以看到某些应用程序的下载趋势。这是cron作业可以完成的典型示例,但systemd计时器可以做同样的事情:#cron-likepopcon.timer[Unit]Description=这描述了popcon数据下载和处理的时刻=Thu*-*-*05:32:07Unit=popcon.service[Install]WantedBy=basic.target实际的popcon.service将执行常规的wget任务,没什么特别的。这里的新内容是OnCalendar=指令。此命令允许您在特定日期的特定时间运行服务。本例中,Thu表示“星期四运行”,*-*-*表示“具体年月日无关紧要”,这些可以翻译为“只在星期四运行,不管年月日”。这样,您就设置了该服务的运行时间。我选择在CET早上5:30左右运行,当时服务器不是很忙。如果您的服务器出现故障而您刚好错过了每周的截止日期,您还可以在同一计时器中使用类似anacron的功能。#popcon.timerwithanacron-likefunction[Unit]Description=这描述了下载和处理popcon数据的时间[Timer]Unit=popcon.serviceOnCalendar=Thu*-*-*05:32:07Persistent=true[Install]WantedBy=basic.target当您将Persistent=指令设置为true时,如果服务器在应该运行时关闭,它会告诉systemd在启动后立即运行该服务。这意味着如果机器在星期四凌晨宕机(比如维护),一旦再次启动,popcon.service将立即执行。之后,每周四早上5点32分恢复运行。到目前为止,非常简单。延迟执行但是,我们将其提升了一个档次并“改进”了基于systemd的监控系统。您应该记住,当您插入相机时,系统会开始拍照。假设您不希望它在安装相机时捕捉您的脸部。您希望将相机服务的启动延迟一两分钟,以便您有时间插入相机并走出框架。为此,首先您必须更改Udev规则以将其指向计时器:ACTION=="add",SUBSYSTEM=="video4linux",ATTRS{idVendor}=="03f0",ATTRS{idProduct}=="e207",TAG+="systemd",ENV{SYSTEMD_WANTS}="picchanged.timer",SYMLINK+="mywebcam",MODE="0666"这个定时器看起来像这样:#picchanged.timer[Unit]Description=inOne连接相机一分钟后,开始运行picchanged[Timer]OnActiveSec=1mUnit=picchanged.path[Install]WantedBy=basic.target连接相机后,Udev规则被触发,它会调用定时器。此计时器启动并等待一分钟(OnActiveSec=1m),然后运行??picchanged.path,它会监视主图片的变化。picchanged.path还负责联系webcan.service,也就是真正用来拍照的服务。在一天中的特定时间启动和停止Minetest服务器在最后一个示例中,我们假设您决定使用systemd作为唯一的依赖项。说真的,systemd几乎已经接管了你的生活。为什么不接受这种必然性呢?您为您的孩子设置了Minetest服务。然而,你也想假装关心他们的教育和成长,给他们布置家庭作业和家务。所以你想确保Minetest只在每晚的特定时间段可用,比如下午5-7点。这和之前的“在特定时间启动服务”是不一样的。编写一个计时器在下午5点启动服务很容易...:#minetest.timer[Unit]Description=Runminetest.service[Timer]OnCalendar=*-*-*17:00:00Unit=minetest.service[Install]WantedBy=basic.target...但是编写一个相应的计时器在特定时刻关闭服务需要更多的横向思考。让我们从最明显的开始-设置计时器:#stopminetest.timer[Unit]Description=Stopminetest.service[Timer]OnCalendar=*-*-*19:05:00Unit=stopminetest.service[Install]WantedBy=basic。target这里棘手的部分是如何告诉stopminetest.service停止Minetest。我们不能从minetest.service传递Minetest服务器的PID。同样在systemd的单元词汇表中,没有明显的命令来停止或禁用正在运行的服务。我们的技巧是使用systemd的Conflicts=指令。它类似于systemd的Wants=指令,但作用相反。如果你有一个包含Wants=a.service指令的b.service单元,当单元启动时,如果a.service尚未运行,b.service将运行它。同样,如果您的b.service单元中有一行内容为Conflicts=a.service,那么systemd将在b.service启动时停止a.service。当两个服务试图同时控制同一个资源时会使用这种机制可能发生冲突的场景,例如当两个服务想要同时访问一台打印机时。通过在最重要的服务上设置Conflicts=,您可以确保它将覆盖最不重要的服务。但是,您将在稍微不同的情况下使用Conflicts=。你可以使用Conflicts=彻底关闭minetest.service:.service没有做任何特别的事情。事实上,它什么都不做。但是因为它包含Conflicts=行,systemd在启动时关闭了minetest.service。你的***Minetest设置中又出现了一个涟漪:你下班迟到了,错过了服务器的启动时间,但是你启动时游戏时间还没有结束,我该怎么办?Persistent=指令(如上所述)在错过启动时间后仍会运行该服务,但此解决方案仍然无效。如果你在上午11点打开服务器,它会启动Minetest,这不是你想要的。你真正需要的是确保systemd仅在下午5点到7点之间启动Minetest的方法:#minetest.timer[Unit]Description=在下午5点到7点之间每分钟运行一次minetest.service[Timer]OnCalendar=*-*-*17。.19:*:00Unit=minetest.service[Install]WantedBy=basic.targetOnCalendar=*-*-*17..19:*:00这一行有两个有趣的地方:(1)17..19不是一个时间点,但是一段时间,在这个场景中是17点到19点;并且,(2)*在分钟字段中表示该服务每分钟运行一次。因此,您可以将其解读为“下午5点到7点之间的每一分钟,运行minetest.service”,但存在一个问题:一旦minetest.service启动并运行,您希望minetest.timer不要再次尝试运行它。你可以在minetest.service中包含一个Conflicts=指令:--serverExecStop=/bin/kill-2$MAINPID[Install]WantedBy=multi-user.target上面的Conflicts=指令将确保minetest.timer在minstest.service成功运行后立即停止。现在,启用并启动minetest.timer:在五点到七点之间,minetest.timer会尝试每分钟启动一次minetest.service。但是,一旦minetest.service开始运行,systemd就会停止minetest.timer,因为它与minetest.service“冲突”,从而阻止计时器在服务已经运行时继续尝试启动该服务。在服务第一次启动时就杀死启动服务的计时器有点违反直觉,但它确实有效。总之,您可能认为有更好的方法来完成上述操作。我在很多文章中都看到过“过度设计”这个词,尤其是在使用systemd计时器代替cron时。但是,本系列文章的目的不是为任何特定问题提供确定的解决方案。它的目的是用systemd来解决尽可能多的问题,甚至到荒谬的地步。其目的是提供大量示例,说明如何使用不同类型的单位及其包含的说明。我们的读者,您,可以在本文中找到所有这些的实际示例。尽管如此,我们还有一件事要做:在下一集中,我们将重点关注套接字和目标,然后我们将完成对systemd单元的介绍。
