Skip to content

Latest commit

 

History

History
314 lines (280 loc) · 10.8 KB

定时任务.md

File metadata and controls

314 lines (280 loc) · 10.8 KB

定时任务

cron

安装

  • centos
    yum install vixie-cron crontabs
    
  • debian
    apt-get install cron
    
  • 大多数发行版都会自带 cron

cron 通常分为三部分

  1. crond 是 cron 在系统内的守护进程,
  2. crontab 是管理 cron 任务的工具
  3. 配置文件
    • 配置文件的位置?

cron 表达式

* * * * *
分 时 日 月 星期
特别的
    @yearly 0 0 1 1 * 每年运行一次
    @monthly 0 0 1 * * 每月运行一次
    @weekly 0 0 * * 0 每星期运行一次
    @daily 0 0 * * * 每日运行一次
    @hourly 0 * * * * 每小时运行一次
            * * * * * 每分钟运行一次 这个就没有特殊的名称了
    @reboot
        将作业配置为在守护程序启动时运行一次。
        由于 cron 通常永远不会重新启动,因此这通常用于系统启动时运行的任务

cron 如何使用

常用的命令

  • 列出定时任务
    crontab -l
    
  • 编辑定时任务
    crontab -e
    
    和直接修改配置文件相比, crontab -e 在退出时会检测一次语法

cron 的实现

  • vixie cron 这个应该是现在最流行的 cron 版本了 https://github.com/vixie/cron
  • busybox 版的 cron https://github.com/mirror/busybox/blob/HEAD/miscutils/crond.c https://github.com/mirror/busybox/blob/HEAD/miscutils/crontab.c
  • 其他流行的实现包括 anacron dcron mcron cronie
  • 对于大多数发行版的 cron 而言
    • cron 是无状态的,
    • cron 在代码里写死了60秒扫描一次配置文件,
      • 为什么cron没有秒级的任务?
        • 因为代码里写死了60秒扫描一次配置文件
      • 为什么是60秒?
        • 大概可能因为是 祖宗之法不可变 吧
    • 扫描配置文件时,遇到符合规则的任务就会运行,
    • 对于单个任务的状态, cron 是不会判断的,不判断上次任务的成功或失败,不判断上次任务运行的时间
  • cron 的实现要比想象中的简单不少
  • 其实现在的 cron 也是通过 systemd 运行的
    crond.service
    systemctl status crond.service
    

使用bash脚本实现的隔秒运行和单例运行

  • 隔秒运行
    * * * * * cron.sh
    #!/bin/bash
    step=1 #间隔的秒数,不能大于60
    for (( i = 0; i < 60; i=(i+step) )); do
        $(php test.php)
        sleep $step
    done
    exit 0
  • 单例运行
    要使用文件锁确保当前只有一个脚本在运行
    flock命令
    例子1
    ```
    #!/usr/bin/env bash
    LOCK_FILE=/var/lock/test.lock
    exec 99>"$LOCK_FILE"
    flock -n 99
    if [ "$?" != 0 ]; then
        echo "$0 already running"
        exit 1
    fi
    #脚本要做的其他事情
    ```
    例子2
    ```
    #!/usr/bin/env bash
    [ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en  "$0"  "$0"  "$@" || :
    # 如果${FLOCKER}环境变量没有设置,则尝试将脚本本身加锁,如果加锁成功,则运行当前脚本,(并且带上原有的参数),否则的话静默退出。
    #脚本要做的其他事情

systemd 的 timer

如何创建定时器

  • 创建一个 service
    • 在 systemd 的配置目录下新建一个名为 MyTimer.service 的文件 /usr/lib/systemd/system/MyTimer.service
    [Unit]
    Description=MyTimer
    
    [Service]
    ExecStart=/bin/bash /path/to/MyTimer.sh
    
    • 可以像这样运行一次测试是否有生效
    systemctl start MyTimer.service
    
  • 然后创建一个 timer
    • 在 systemd 的配置目录下新建一个名为 MyTimer.service 的文件 /usr/lib/systemd/system/MyTimer.timer
    [Unit]
    Description=Runs mytimer every hour
    
    [Timer]
    # 定时器
    OnUnitActiveSec=1h
    # 定时器触发的任务
    Unit=mytimer.service
    
    [Install]
    # 开机启动时的依赖项,大多数情况下都是填这个
    WantedBy=multi-user.target
    
  • 最后把 timer 加入到开机启动中
    systemctl enable MyTimer.timer
    

定时器的相关命令

列出所有定时器
    systemctl list-timers
systemctl 的命令也能直接用在 定时器中
    start stop status enable disable
查看所有单元
    systemctl list-unit-files
查看所有 Service 单元
    systemctl list-unit-files --type service
查看所有 Timer 单元
    systemctl list-unit-files --type timer

和 cron 比较

  • systemed 的 timer 可以实现 秒级 任务,但 crond 不可以
  • systemed 的 timer 比 crond 的灵活很多,基本接近 windows 的计划任务了

Windows 的 计划任务

  • windows 的 计划任务 包括了 开机启动 和 定时任务
  • 以前用 at 命令操作,现在用 schtasks 命令操作
  • 用图形界面也是可以的
    taskschd.msc
    https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/schtasks
    https://learn.microsoft.com/zh-cn/windows/win32/taskschd/task-scheduler-start-page
    https://learn.microsoft.com/zh-cn/windows/win32/taskschd/using-the-task-scheduler
    
  • schtasks
    • 查询任务
      schtasks /Query
      schtasks /Query /TN "\Microsoft\Windows\WwanSvc\NotificationTask"
      schtasks /Query /V /TN "\Microsoft\Windows\WwanSvc\NotificationTask"
      
    • 删除任务
      schtasks /Delete /TN taskname /F
      taskname 是任务名
      /F 是强制执行
      
    • 创建任务
      schtasks /Create /TN taskname /TR taskrun
      定时任务的表达式有一点混乱,最好还是去看文档
          每分钟运行一次
              schtasks /create /sc minute /mo 1 /tn "task name" /tr "command"
          开机启动,设置开机启动的任务需要管理员权限
              schtasks /create /sc ONSTART /tn "task name onstart" /tr "command"
      
  • 用 powershell 的 cmdlets 也能创建 windows 的定时任务
    https://learn.microsoft.com/en-us/powershell/module/scheduledtasks
    https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.utility/new-timespan
    
  • 使用 powershell 创建定时任务
    • 这是分开创建的,分开创建可以使用多个触发器
      $Act1 = New-ScheduledTaskAction -Execute "command";
      $Time = New-ScheduledTaskTrigger -Once -At (Get-Date)  -RepetitionInterval (New-TimeSpan -Minutes 1) ;
      Register-ScheduledTask -TaskName "SoftwareScan" -Trigger $Time -Action $Act1;
      
    • 这是合成一条命令
      每分钟运行一次
      Register-ScheduledTask -TaskName "SoftwareScan" -Trigger (New-ScheduledTaskTrigger -Once -At (Get-Date)  -RepetitionInterval (New-TimeSpan -Minutes 1)) -Action (New-ScheduledTaskAction -Execute "command");
      开机启动
      Register-ScheduledTask -TaskName "SoftwareScan" -Trigger (New-ScheduledTaskTrigger -AtStartup) -Action (New-ScheduledTaskAction -Execute "command");
      
    • 使用多个触发器的例子
      每天11:00和23:00运行一次
      $Act1 = New-ScheduledTaskAction -Execute "command";
      $Time1 = New-ScheduledTaskTrigger -Daily -At 11am;
      $Time2 = New-ScheduledTaskTrigger -Daily -At 11pm;
      Register-ScheduledTask -TaskName "SoftwareScan2" -Trigger ($Time1, $Time2) -Action $Act1;
      
  • 计划任务一个触发器只能设定一个时间,但一个任务可以有多个触发器,schtasks命令只能设置一个触发器
  • 如果计划任务运行的是 bat 或 ps 或 bash 脚本,任务运行时会弹出一个黑框
    • 如果要隐藏黑框,需要以管理员权限生成任务,或者用 vbs 的方式调用脚本,但vbs的方式很容易被杀毒软件拦截
    schtasks /create /sc minute /mo 1 /ru System /tn "acme_cron" /tr "command"
    Register-ScheduledTask -User System -TaskName "SoftwareScan" -Trigger (New-ScheduledTaskTrigger -Once -At (Get-Date)  -RepetitionInterval (New-TimeSpan -Minutes 1)) -Action (New-ScheduledTaskAction -Execute "command");
    
  • 通过 xml 文件你创建计划任务

在 windows 下如何运行 cron

  • 关键是要能每分钟扫描一次 cron 的配置文件,然后执行符合规则的任务
  • 有一个能每分钟运行一次或持续运行的程序用来扫描 cron 的配置文件
    • 直接运行一个命令行,然后不关闭窗口
    • 让程序以服务的形式运行
      • 可以直接在代码里写好
      • 也可以用 nssm 或 winsw 这类工具把普通的程序封装成服务
    • 使用 计划任务 ,每分钟运行一次
  • 能解释 cron 表达式
    • 这种库在 github 十分的多,而且各种语言实现的都有,但怎样实现 @reboot ?
    • 如果是 一直运行的命令行 或 服务 的形式
      • 就一开始启动时运行一次,以后就忽略
    • 如果是 计划任务 ,每分钟运行一次
      • 通过 系统启动时间 或 系统运行时长 来判断是否需要运行 @reboot
      wmic path Win32_OperatingSystem get LastBootUpTime
      (get-date) - (gcim Win32_OperatingSystem).LastBootUpTime
      (Get-Date (Get-CimInstance -ClassName win32_operatingsystem).LastBootUpTime -UFormat %s).ToString() // 开机时间的10位时间戳
      锁定 注销 睡眠 休眠 都 不会计入停机时间
      

其他

Linux 的 at 和 atq

at 和 atq 通常用于一次性任务

Windows 的 at

还有哪些好用的定时任务或计划任务工具?

  • mysql 的事件调度器 (Event Scheduler)
  • PostgreSQL 的 PgAgent 也能实现定时任务