Linux下定时任务的打开姿势

最近在帮学校网络中心搞后端开发时填了一些和服务器端定时服务有关的坑。比如定时查询用户流量是否超出使用警戒值以发送提示短信,定时查询用户在线设备数量踢下线之类的。

其中有些操作其实可以在MySQL中用触发器完成,不过由于历史和技术问题(学校的上古版本MySQL数据库用了Cobar做中间件,必须用同样上古的Java驱动才能连接成功……同时也不能直接加触发器和存储过程什么的),还是得写成Shell或者Python的定时脚本完成任务。


让程序sleep一会

说到定时任务我的第一反应是写个脚本后台运行,完成任务之后sleep一段时间,之后再次执行任务,大概就像这样:

def foo():
    while True:
        do something
        time.sleep(24 * 60 * 60)

foo()

一般在终端里我们可以在命令后面加上 “&” 让它后台运行。 不过当用户注销或者网络断开时,终端会收到HUP信号从而关闭其所有子进程。我们需要使用nohup或者screen这样的工具来避免HUP信号的影响。

当然,这种方式执行所谓的定时任务存在着许多问题。由于网络或者其它因素脚本挂掉了怎么办?


用Systemd守护你的后台脚本

Systemd是一个系统管理守护进程、工具和库的集合,是RedHat主导开发的用于取代initd的系统管理工具。网上对这个东西褒贬不一,而且它也还在快速迭代开发中。不过目前大多数主流Linux发行版都选择它作为系统管理工具了。

你可以通过命令systemctl管理你通过Systemd守护的脚本。通过一些简单的命令就能随时关闭、重启你的脚本。

可以在/lib/systemd/system/目录下写一个配置文件script.service来管理你的脚本:

[Unit]
Description=My Script
[Service]
Type=simple
WorkingDirectory=/home/pointstone/script
ExecStart=/usr/bin/python3 main.py
[Install]
WantedBy=multi-user.target

执行下述命令注册,重启你的脚本:

systemctl daemon-reload

systemctl enable traffic-alert.service

systemctl start traffic-alert.service


crontab执行定时任务

虽然Systemd成功让我们的脚本更稳定了一点,不过脚本挂起时依然占用着计算机的资源。我能让一个脚本,或者是一个命令每隔一段时间就在系统里执行一次么?答案是肯定的,用crontab这个工具就能完成。

通过crontab 命令,我们可以在固定的间隔时间执行指定的系统指令或 shell script脚本。时间间隔的单位可以是分钟、小时、日、月、周及以上的任意组合。

向cron进程提交一个crontab文件之前,首先要设置环境变量EDITOR。cron进程根据它来确定使用哪个编辑器编辑crontab文件。比如我习惯使用Vim,我就在用户HOME目录里的.bashrc文件里加入

EDITOR=vim; export EDITOR

接着执行下述命令开始添加我们的crontab任务

crontab -e

每个crontab任务最前面都有5个参数表示定时执行的时间,它们分别表示分钟、小时、日(公历)、月、日(礼拜)。然后接下来跟着每到时间点它要执行的命令。

举几个简单的栗子:)

每天下午六点半删除某个文件夹里的内容:

30 18 * * * rm /home/me/tmp/*

每个月10号和每周一的零点5分和零点10分执行任务

5,10 0 10 * 1 do something

全部放空,默认每分钟执行一次任务

* * * * *  do something



总结起来,crontab是打开定时任务比较正确的姿势啊!