在linux下执行定期任务可以使用crontab,目前mac os也可以使用它,不过已不推荐使用。推荐做法是采用plist脚本,plist脚本可以设置执行的动作,时间间隔等其他一些信息。另外crontab的最小时间间隔是一分钟,使用plist脚本原则上时间间隔可以为一秒。

定时任务拉取数据原则:拉取当前系统时间之前5分中之前的数据

定时任务每月一号跑10万条数据。如果按照每5分钟跑一次配置任务,数据跑完了后空跑脚本,造成性能的浪费。最好的方法每月1号跑一次,因为定时任务机制不会超时php-cli,每次操作300条数据,可以在任务内部循环do..while实现

public function myCronJob() {
    $page = 1;
    do {
        $workParking = $listParkingTmp['data']['list'];
        $page++;
    } while ($workParking);
}

 PHP版的定时任务

<?php
$a = time();
ignore_user_abort(); //关掉浏览器,PHP脚本也可以继续执行.
set_time_limit(3000); // 通过set_time_limit(0)可以让程序无限制的执行下去
$interval = 5; // 每隔5s运行 
do {
    sleep($interval);
    
    //查询订单接口
    echo $i . "---" . (time() - $a) . "<br/>";
    $paid_list = $order_logic->getCallBackList($order_id); 
} while (empty($paid_list));
?>

Mac PLIST

plist脚本存放路径为/Library/LaunchDaemons或/Library/LaunchAgents,其区别是后一个路径的脚本当用户登陆系统后才会被执行,前一个只要系统启动了,哪怕用户不登陆系统也会被执行

可以通过两种方式来设置脚本的执行时间。一个是使用StartInterval,它指定脚本每间隔多长时间(单位:秒)执行一次;另外一个使用 StartCalendarInterval,它可以指定脚本在多少分钟、小时、天、星期几、月时间上执行,类似如crontab的中的设置。

一个简单例子如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.yangyz.cron.test.plist</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/yangyz/plist-test.sh</string>
    </array>
    <key>KeepAlive</key>
    <false/>
    <key>RunAtLoad</key>
    <true/>
    <key>StartInterval</key>
    <integer>60</integer>
</dict>
</plist>

其中key是plist脚本定义的属性,紧跟着的下一行是该属性对应的值。上述脚本是每间隔60秒执行一次/Users/yangyz/plist- test.sh这个shell脚本,也可以使用StartCalendarInterval来替换StartInterval达到同样的效果,例如:

<key>StartCalendarInterval</key>
<dict>
  <key>Minute</key>
  <integer>0</integer>
</dict>

上述设置的意思为每天的每个小时的第0分钟执行,也即使每60秒执行一次。plist脚本中定义的属性以及具体的含义,可以参看苹果官方网站的说明

launchctl命令可以控制plist脚本停止或重新加载。例如:

#停止脚本com.yangyz.cron.test.plist运行
launchctl unload /Library/LaunchDaemons/com.yangyz.cron.test.plist 

#启动脚本com.yangyz.cron.test.plist运行
launchctl load /Library/LaunchDaemons/com.yangyz.cron.test.plist

 如果执行上面命令看到launchctl: Dubious ownership on file (skipping): /Library/LaunchDaemons/com.yangyz.cron.test.plist这样的错误,其原因是该脚本的owner和当前执 行操作用户不一致。使用chown修改一下即可

Linux crontab

Linux crontab定时执行任务 命令格式与详细例子,大家可以参考下

# Example of job definition:
# .---------------- 分钟 (0 - 59)
# |  .------------- 小时 (0 - 23)
# |  |  .---------- 一个月中的第几天 (1 - 31)
# |  |  |  .------- 月份 (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- 星期中星期几 (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed

基本格式 :

*  *  *  *  *  command
分 时   日   月  周   命令

  • 第1列表示分钟1~59 每分钟用*或者 */1表示
  • 第2列表示小时1~23(0表示0点)
  • 第3列表示日期1~31
  • 第4列表示月份1~12
  • 第5列标识号星期0~6(0表示星期天
  • 第6列要运行的命令

crontab例子

* * * * * /bin/ls
每一分钟执行一次 /bin/ls:

30 21 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每晚的21:30重启apache

45 4 1,10,22 * * /usr/local/etc/rc.d/lighttpd restart
#上面的例子表示每月1、10、22日的4 : 45重启apache。

10 1 * * 6,0 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每周六、周日的1 : 10重启apache。

0,30 18-23 * * * /usr/local/etc/rc.d/lighttpd restart
上面的例子表示在每天18 : 00至23 : 00之间每隔30分钟重启apache。

0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart
上面的例子表示每星期六的11 : 00 pm重启apache。

* */1 * * * /usr/local/etc/rc.d/lighttpd restart
每一小时重启apache

* 23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart
#晚上11点到早上7点之间,每隔一小时重启apache

0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart
每月的4号与每周一到周三的11点重启apache

0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart
一月一号的4点重启apache

比如说root查看自己的cron设置:crontab -u root -l
再例如,root想删除fred的cron设置:crontab -u fred -r
在编辑cron服务时,编辑的内容有一些格式和约定,输入:crontab -u root -e

修改/etc/crontab这种方法只有root用户能用,这种方法更加方便与直接直接给其他用户设置计划任务,而且还可以指定执行shell等等, crontab -e这种所有用户都可以使用,普通用户也只能为自己设置计划任务。然后自动写入/var/spool/cron/usename

在使用之前首先通过which php命令找到自己的php安装到了哪里,西面能用到,我的打印出来是/usr/local/php/bin/php
为了知道自己写的php到底有没有被调用,在php写了一个简单的文件写入函数,我将当前的时间写入到一个test.txt中,只要查看test.txt, 我就知道php是有没有调用,什么时候调用,这样就可以大致看出来,自己设置的调用时间是不是被正确执行了。

<?php
$fp = fopen("test.txt","a+");
fwrite($fp, date('Y-m-d H:i:s')."****"."\r\n");
fclose($fp);
?>

配置crontab:

* * * * * root php /var/www/html/iu-deployer/current/artisan schedule:run >> /var/logs/cron.log 2>&1
* * * * * root /bin/bash /var/www/html/a.sh >> /var/logs/sh.log 2>&1

然后保存退出

同步linux服务器系统时间

Linux服务器运行久时,系统时间就会存在一定的误差,一般情况下可以使用date命令进行时间设置,但在做数据库集群分片等操作时对多台机器的时间差是有要求的,此时就需要使用ntpdate进行时间同步

#同步linux服务器系统时间
*/5 * * * * ntpdate ntp1.aliyun.com >/dev/null 2>&1

关于定时任务的思考:每天统计1天的对账单定时脚本,当天的对账单不能做到及时数据,如果将定时任务做成每3分跑一次服务器压力又很大。解决方法:当有查询报表功能时,触发统计当天的统计业务逻辑即可

定时任务执行失败可能原因

在linux下用crontab启动定时sh脚本,放到crontab中死活没反应,这是可能的原因:

  • 检查 crontab服务是否正常service crond status
  • 看日志:cat /var/log/cron 或 /var/log/messages。
  • 看日志完全没反应,没有脚本执行记录,crontab也是运行状态,这时可能的原因是编辑定时任务时带了中文空格
  • 要赋予执行权限,如 chmod +x xxx.sh   就是给xxx.sh这个脚本赋予执行权限
  • 还有一个原因可能脚本开头 #!/bin/bash 写错了或者少写了
  • crontab定时任务要写全路径,全路径!
  • 检查脚本是否需要用到的变量

近期某服务器的crontab,每天未正常执行,检查日志发现大量报错,如下:

1.chage -l ${username}查看用户密码期限相关信息

chage -l root
-----------------------------------------
Last password change                                    : Jun 29, 2016
Password expires                                        : Sep 27, 2016
Password inactive                                       : never
Account expires                                         : never
Minimum number of days between password change          : 0
Maximum number of days between password change          : 90
Number of days of warning before password expires       : 7

 2.修改Maximum number of days between password change期限至永久

chage -M 99999 root;
-----------------------------------------
Last password change					: Aug 04, 2018
Password expires					: never
Password inactive					: never
Account expires						: never
Minimum number of days between password change		: 7
Maximum number of days between password change		: 99999
Number of days of warning before password expires	: 7

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐