• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

使用 Cron 作业安排任务

Cron 作业用于安排任务在服务器上运行。它们最常用于自动化系统维护或管理。但是,它们也与 Web 应用程序开发相关。在很多情况下,Web 应用程序可能需要定期运行某些任务。今天我们将探讨 Cron Jobs 的基本原理。

定义

首先让我们熟悉与该主题相关的术语。

“Cron”是类 Unix 操作系统(Linux、FreeBSD、mac OS 等)中基于时间的作业调度程序。这些工作或任务被称为“Cron Jobs”。

在这些系统上运行有一个 cron“守护进程”。守护进程是一直在后台运行的程序,通常由系统启动。这个 cron 守护进程负责按时启动这些 cron 作业。

该计划驻留在一个名为“crontab”的配置文件中。那是列出所有任务及其计时器的地方。

为什么使用 Cron 作业?

服务器管理员长期以来一直在使用 cron 作业。但由于本文的目标受众是 Web 开发人员,让我们看一些与该领域相关的 cron 作业用例:

  • 如果您有一个会员站点,其中帐户有到期日期,您可以安排 cron 作业以定期停用或删除超过其到期日期的帐户。

  • 您可以发送每日时事通讯电子邮件。

  • 如果您的数据库中有汇总表(或物化视图),则可以使用 cron 作业定期更新它们。例如,您可以将每个网页点击存储在一个表中,但另一个汇总表可能包含每日流量汇总。

  • 您可以在一定的时间间隔内过期和擦除缓存的数据文件。

  • 您可以自动检查您的网站内容是否有损坏的链接,并定期将报告通过电子邮件发送给您自己。

  • 您可以安排长时间运行的任务从命令行脚本运行,而不是从 Web 脚本运行。比如编码视频,或者发送大量电子邮件。

  • 您甚至可以执行一些简单的操作,例如获取最新的推文,并将其缓存在文本文件中。

句法

这是一个简单的 cron 作业:

110 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&1

有两个主要部分:

  1. 第一部分是10 * * * *。这是我们安排计时器的地方。

  2. 该行的其余部分是从命令行运行的命令。

此示例中的命令本身包含三个部分:

  1. /usr/bin/php:PHP 脚本通常不能自行执行。因此我们需要通过 PHP 解析器来运行它。

  2. /www/virtual/username/cron.php: 这只是脚本的路径。

  3. > /dev/null 2>&1: 这部分是处理脚本的输出。稍后再谈。

时序语法

如上所述,这是 cron 作业字符串的第一部分。它决定了 cron 作业运行的频率和时间。

它由五个部分组成:

  1. 分钟

  2. 小时

  3. 一个月的一天

  4. 星期几

这是一个插图:

使用 Cron 作业安排任务  第1张

星号

很多时候,您会看到星号 ( *) 而不是数字。这代表该职位的所有可能数字。例如,分钟位置的星号将使其每分钟运行一次。

我们需要看几个例子来完全理解这个语法。

例子:

此 cron 作业将始终每分钟运行一次:

1* * * * * [command]

此 cron 作业将在零分钟运行,每小时一次(即每小时一次的 cron 作业):

10 * * * * [command]

这也是一个每小时一次的 cron 作业,但在整点后 15 分钟运行(即 00:15、01:15、02:15 等):

115 * * * * [command]

这将在每天凌晨 2:30 运行一次:

130 2 * * * [command]

这将在每月的第二天午夜运行一次(例如,1 月 2 日凌晨 12:00 或 2 月 2 日凌晨 12:00):

10 0 2 * * [command]

这将在星期一每小时运行一次(即一天 24 次,但仅限于星期一):

10 * * * 1 [command]

您可以使用以逗号分隔的多个数字。这将在 0、10 和 20 分钟每小时运行 3 次:

10,10,20 * * * * [command]

除法运算符也被使用。这将每小时运行 12 次,每 5 分钟一次:

1*/5 * * * * [command]

破折号可用于指定范围。这将在上午 5:00 到上午 10:00 之间每小时运行一次:

10 5-10 * * * [command]

还有一个特殊的关键字可以让您在每次重新启动服务器时运行一个 cron 作业:

1@reboot [command]

设置和管理 Cron 作业

有几种不同的方法可以创建和管理您的 cron 作业。

控制面板

许多网络托管公司为其客户提供控制面板。如果您是其中之一,您也许可以在控制面板中找到一个部分来管理您的 cron 作业。

使用 Cron 作业安排任务  第2张

编辑 Crontab

运行此命令将启动 vi(文本编辑器)并让您编辑 crontab 的内容。如果您的系统上没有任何 crontabs 文件,该命令将创建一个。

1crontab -e

使用 Cron 作业安排任务  第3张

因此,熟悉基本的 vi 命令会有所帮助,因为它与您可能使用过的任何其他文本编辑器完全不同。

如果您只想查看现有的 crontab 而不对其进行编辑,可以运行以下命令:

1crontab -l

使用 Cron 作业安排任务  第4张

要删除 crontab 的内容:

1crontab -r

使用 Cron 作业安排任务  第5张

加载文件

您可以将所有 cron 作业写入一个文件,然后将其推送到 crontab 中:

1crontab cron.txt

请小心,因为这将使用此文件内容覆盖所有现有的 cron 作业,而不会发出警告。

注释

您可以在#字符后添加注释。

# This cron job does something very important
10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&1

设置电子邮件

正如我之前提到的,默认情况下,crons 的输出通过电子邮件发送,除非您丢弃它们或将它们重定向到文件。该MAILTO设置可让您设置或更改将其发送到的电子邮件地址

MAILTO="username@example.com"
# This cron job does something very important
10 * * * * /usr/bin/php /www/virtual/username/cron.php > /dev/null 2>&1

使用 PHP 解析器

CGI 脚本默认是可执行的,但 PHP 脚本不是。他们需要运行 PHP 解析器。这就是为什么我们需要将解析器的路径放在脚本的路径之前。

1* * * * * /usr/bin/php [path to php script]

有时它可能位于另一个位置,例如:/usr/local/bin/php。要找出答案,您可以尝试在命令行中运行它:

1which php

使用 Cron 作业安排任务  第6张

处理输出

如果您不处理 cron 脚本的输出,它会将它们作为电子邮件发送到您在服务器上的用户帐户。

丢弃输出

如果您将> /dev/null 2>&1 cron 作业命令(或任何命令)放在末尾,则输出将被丢弃。

使用 Cron 作业安排任务  第7张

右括号 ( >) 用于重定向输出。/dev/null 就像一个输出黑洞。系统会忽略任何去那里的东西。

这部2>&1分会导致 STDERR(错误)输出重定向到 STDOUT(正常)输出。所以这也最终出现在/dev/null.

输出到文件

要将 cron 输出存储在文件中,请>再次使用右括号 ( ):

110 * * * * /usr/bin/php /www/virtual/username/cron.php > /var/log/cron.log

这将每次重写输出文件。如果您想在文件末尾追加输出而不是完全重写,请使用双右括号 ( >>) 代替:

110 * * * * /usr/bin/php /www/virtual/username/cron.php >> /var/log/cron.log

可执行脚本

通常,您需要像我们一直在做的那样在命令的开头指定解析器。但实际上有一种方法可以让您的 PHP 脚本像 CGI 脚本一样从命令行执行。

您需要将解析器的路径添加为脚本的第一行:

#!/usr/local/bin/php
<?php
 
echo "hello world\n";
 
// ...
 
?>

还要确保设置适当的权限(如 755)以使文件可执行。

使用 Cron 作业安排任务  第8张

当您有一个可执行脚本时,cron 作业可以像这样更短:

110 * * * * /www/virtual/username/hello.php

防止 Cron 作业冲突

在某些情况下,您可能经常运行 cron 作业,如果它们的运行时间比频率本身长,您可能不希望它们发生冲突。

例如,您可能每分钟都有一个 cron 作业运行。然而,每隔一段时间,运行时间可能会超过一分钟。这可能会导致同一 cron 脚本的另一个实例在前一个完成之前开始运行。您可以通过这种方式创建太多繁忙的进程,并且如果它们继续彼此减慢,则可能会使服务器崩溃,并导致随着时间的推移创建更多的进程。

这个问题可以通过文件锁定来解决,更具体地说是非阻塞 ( LOCK_NB) 类型的文件锁定。(如果你不熟悉文件锁定,我建议你先阅读它。)

您可以将此代码添加到 cron 作业脚本中:

$fp = fopen('/tmp/lock.txt', 'r+');
 
if(!flock($fp, LOCK_EX | LOCK_NB)) {
    echo 'Unable to obtain lock';
    exit(-1);
}
 
/* ... */
 
fclose($fp);

使用常规文件锁,flock()如果存在现有锁,函数调用将阻塞脚本。一旦锁消失,它就会释放。但是,对于非阻塞锁,例如上面的代码,函数调用不会停止脚本,但FALSE如果存在锁,它会立即返回。所以在这种情况下,当我们看到存在一个锁时,我们可以立即退出脚本,这表明另一个 cron 作业当前正在运行。

阻止对 Cron 作业的 Web 访问

当您使用 PHP 等 Web 脚本语言编写 cron 作业时,您可能希望确保没有人可以通过仅从浏览器加载它来执行它。一个简单的选择是将这些脚本存储在您的 Web 文件夹之外。但是,对于某些开发人员来说,如果他们想将他们的 cron 作业脚本保留在他们的 Web 应用程序文件夹中,这可能不切实际或不理想。

如果将所有 cron 作业脚本放在一个文件夹中,则可以通过将此行放在.htaccess文件中来阻止访问:

1deny from all

或者您也可以通过将此行放在开头来逐个拒绝对脚本的访问:

1if (isset($_SERVER['REMOTE_ADDR'])) die('Permission denied.');

这将确保当从 Web 访问脚本时,它将立即中止。

Cron 作业监控 

设置 cron 作业并假设它们都将按预期工作并不是一个好习惯。拥有一个工具来监控您正在运行的任务并确保及时发现任何失败、损坏或延迟的 cron 作业,这不是很酷吗?

Cron 作业监控允许您监控您的 cron 作业并提前预防任何延迟或崩溃。有一些监控工具可用,最流行的是Cronitor。

使用 Cron 作业安排任务  第9张

Cronitor允许您捕获每个 cron 作业的状态、指标和输出,并在出现任何问题时向相关人员发出警报。

它甚至允许您与流行的消息传递平台(如 slack、Microsoft 团队、SMS 和电子邮件)集成,以确保按时发送故障警报。

结论

感谢您的阅读。尽管 cron 作业看起来只是系统管理员的工具,但它们实际上与多种 Web 应用程序相关。


文章目录
  • 定义
  • 为什么使用 Cron 作业?
    • 句法
    • 时序语法
      • 星号
      • 例子:
    • 设置和管理 Cron 作业
      • 控制面板
      • 编辑 Crontab
      • 加载文件
      • 注释
    • 设置电子邮件
    • 使用 PHP 解析器
    • 处理输出
      • 丢弃输出
      • 输出到文件
    • 可执行脚本
    • 防止 Cron 作业冲突
    • 阻止对 Cron 作业的 Web 访问
    • Cron 作业监控
    • 结论
  • 发表评论