xfra35/f3-cron

PHP Fat-Free 框架的作业调度

v1.2.1 2018-06-19 08:29 UTC

This package is auto-updated.

Last update: 2024-08-26 20:10:51 UTC


README

PHP Fat-Free 框架的作业调度

此插件为Fat-Free 框架提供,可以帮助您直接从您的Web应用中控制作业调度。

安装

要安装此插件,只需将lib/cron.php文件复制到您的lib/AUTOLOAD文件夹中。

操作和基本用法

此插件为您的应用程序提供外部接口以运行计划任务。该接口由自动添加到您的应用程序中的2个路由组成

  • GET /cron检查到期的任务并执行它们
  • GET /cron/@job触发特定任务

默认情况下,此接口仅通过CLI模式访问,并旨在由服务器作业调度程序调用

  1. Unix cron或Windows任务计划程序每分钟(或更慢的速度)调用index.php /cron
  2. index.php /cron在该时间检查到期的任务并执行它们,如果可能的话,异步执行。

第1步

配置您的服务器作业调度程序,使其每分钟调用一次php index.php /cron

以下是在*nix服务器上执行此操作的示例,假设您的应用程序位于/path/to/app/index.php

  • 创建一个名为,例如,mycrontab的文件,包含以下行
* * * * * cd /path/to/app; php index.php /cron
  • 使用以下命令使用它配置cron
crontab mycrontab

注意1:根据您的托管方式,您可能需要要求您的提供商执行此步骤。

注意2:如果您的cron作业需要磁盘写入访问,请注意UNIX用户权限

第2步

实例化Cron类,并使用以下命令定义作业列表和频率

//index.php
$f3=require('lib/base.php');
...
$cron=Cron::instance();
$cron->set('Job1','App->job1','@daily');
$cron->set('Job2','App->job2','@weekly');
...
$f3->run();

就这样!

Job1将每天运行,Job2将每周运行。

调度格式

Crontab

每个作业都使用(几乎)标准的crontab格式进行调度,该格式由5个用空格分隔的字段组成

 * * * * *
 │ │ │ │ │
 │ │ │ │ │
 │ │ │ │ └───── day of week (0 - 6) (0 to 6 are Sunday to Saturday)
 │ │ │ └────────── month (1 - 12)
 │ │ └─────────────── day of month (1 - 31)
 │ └──────────────────── hour (0 - 23)
 └───────────────────────── min (0 - 59)

每个字段可以是

  • 一个*,表示任何
  • 一个数字:3
  • 一个范围:1-4(等于1,2,3,4
  • 一个数字列表或范围:1-4,6,8-10

范围具有默认的步长值为1,可以使用/进行调整

  • 1-6/21,3,5相同
  • */31,4,7,10(月份列)相同

示例

$cron->set('Job1','App->job1','* * * * *'); // runs every minute
$cron->set('Job2','App->job2','*/5 * * * *'); // runs every 5 minutes
$cron->set('Job3','App->job3','0 8 * * 1'); // runs every Monday at 08:00
$cron->set('Job4','App->job4','0 4 10 * *'); // runs the 10th of each month at 04:00
$cron->set('Job5','App->job5','0 0 * */3 *'); // runs on a quarterly basis

预设

为了便于阅读,可以定义预设

$cron->preset('weekend','0 8 * * 6'); // runs every Saturday at 08:00
$cron->preset('lunch','0 12 * * *'); // runs every day at 12:00
$cron->set('Job6','App->job6','@weekend');
$cron->set('Job7','App->job7','@lunch');

默认定义以下预设

  • @yearly@annually <=> 0 0 1 1 *
  • @monthly <=> 0 0 1 * *
  • @weekly <=> 0 0 * * 0
  • @daily <=> 0 0 * * *
  • @hourly <=> 0 * * * *

选项

日志记录

如果设置$cron->log=TRUE,则每个成功执行的作业都将记录在位于LOGS文件夹中的cron.log文件中。

Web界面

默认情况下,路由GET /cronGET cron/@job仅适用于CLI模式,这意味着对它们的HTTP请求将引发404错误。

您可以通过设置 $cron->web=TRUE 来启用 Web 路由。

在这种情况下,/cron 可以通过 HTTP 以周期性方式触发,例如通过您的 Web 应用程序,或通过 Web crontab 服务,甚至通过您自己的 crontab。

* * * * * curl http://mydomain.tld/cron

脚本路径

默认情况下,异步调用的脚本位于当前工作目录中的 index.php

如果您需要调整此值,请参考以下情况:

  • 您的 Web 根目录与您的应用程序根目录不同(例如:index.php 位于 www/ 中,并使用 chdir('..') 开始)
  • 所有调度都在一个单独的文件中处理(例如:使用 cron.php 而不是 index.php

示例

$cron->script='htdocs/index.php';//relative to app root
$cron->script=__DIR__.'/cron.php';//absolute path

PHP二进制路径

默认情况下,用于触发异步作业执行的 PHP 二进制文件是 phpphp-cli(智能猜测)。

如果您需要调整此值,如果这些值都不对应于可执行的 PHP CLI 二进制文件,或者它们不在路径中,请参考以下内容:

示例

$cron->binary('/home/myphp-cli');

每次实例化类时都会检查 PHP 二进制文件的有效性,这可能会导致性能下降(请参阅 #9)。

您可以通过使用第二个参数强制路径来跳过此检查

$cron->binary('/home/myphp-cli',TRUE); // set PHP binary path, whether it's valid or not

在这种情况下,您负责提供正确的路径。

INI配置

可以通过使用 CRON 变量从 .ini 文件内部进行配置。例如

[CRON]
log = TRUE
web = FALSE
script = /path/to/index.php
binary = /path/to/php

[CRON.presets]
lunch = 0 12 * * *

[CRON.jobs]
Job1 = App->job1, * * * * *
Job2 = App->job2, @lunch
Job3 = App->job3, @hourly

如果您需要强制 PHP 二进制文件路径,只需将 TRUE 作为第二个参数传递

[CRON]
binary = /path/to/php, TRUE

重要:在运行应用程序之前,不要忘记实例化类

//index.php
$f3=require('lib/base.php')
$f3->config('cron.ini');
Cron::instance(); // <--- MANDATORY
$f3->run();

异步性

如在第 1 步中配置的那样,cron 插件每分钟实例化一次。每个实例都是独立运行的。

在一个实例中,可能有多个即将到来的作业,这些作业可以同步或异步运行。

如果您想在实例中异步运行即将到来的作业,您需要

注意:插件将自动检测作业是否可以异步运行。如果不能,作业将同步执行,这可能会花费更长的时间,并在作业失败的情况下增加队列丢失的风险。

常见错误

UNIX用户权限

如果您的某个 crontab 作业将数据写入磁盘,如果 crontab 用户和 Web 服务器用户都尝试写入相同的文件,您可能会遇到一些权限问题。

例如,让我们假设您的 crontab 作业作为 root 执行,并渲染一个 HTML 模板以嵌入到报告电子邮件中。然后,当 Web 服务器下一次尝试重新编译此模板时,它将不允许修改位于 $f3->TEMP 的临时文件,Web 用户将遇到 500 错误。

请参阅 此问题 以获取另一个示例。

以下是两种不同的修复此类问题的方法

  • 确保您的 crontab 作业由 Web 服务器用户执行,使用 crontab -u www mycrontab(其中 www 是 Web 服务器用户的名称)
  • 确保 Web 服务器用户和 crontab 用户属于同一 UNIX 组,并将组写入权限授予可写文件夹(例如 chmod -R g+w /srv/www/tmp

重叠作业

如果一个作业运行时间超过了其设计的时间,一个实例可能会与另一个实例重叠(例如:一个每 5 分钟运行一次,但需要 6 分钟完成的作业)。

根据作业的类型,这种情况可能是不希望的(数据损坏的风险)。

如果情况是这样,您应该使用以下解决方案之一来防止作业重叠

设置最大执行时间

在CLI模式下,最大执行时间默认为0。这意味着脚本可以无限运行。

将该参数设置为略小于作业频率的值,可以防止作业重叠。

注意:不要忘记发送作业失败的报告,否则你可能会遇到所有作业都默默失败的情况。

使用资源锁定机制

在您的应用程序代码中,您可以使用锁文件或数据库标志来跟踪正在运行的作业,这样两个cron实例就不能同时执行相同的作业。

注意:不要忘记处理过期的锁。

或者,您可以使用flock二进制文件,它提供自动锁管理。请注意,这个解决方案略有不同,因为它防止两个cron实例(而不是作业)同时执行:如果"作业1"仍在运行,则"作业1"和"作业2"都将被跳过。尽管如此,这个解决方案很容易实现:只需将步骤1中定义的crontab替换为以下内容

* * * * * cd /path/to/app; flock -n cron.lock php index.php /cron

注意:只要cron有写入权限,cron.lock可以放在任何位置。

API

$cron = Cron::instance();

日志

成功执行作业的记录(默认=FALSE)

$cron->log=TRUE;// enable logging

Web界面

Web界面(默认=FALSE)

$cron->web=TRUE;// enable web interface

脚本

调用异步脚本的路径(默认='index.php')

默认在当前工作目录中为index.php

$cron->script='htdocs/index.php';//relative to app root
$cron->script=__DIR__.'/cron.php';//absolute path

clipath

脚本的别名 [已弃用]

binary

PHP CLI二进制文件的路径(默认='php'或'php-cli')

echo $cron->binary;// php

binary( $path, $force=FALSE )

如果路径有效(这意味着它可以被执行并且是CLI),则设置PHP CLI二进制文件路径

如果$force=TRUE,则强制路径而不进行验证检查。此选项可用于性能优化(请参阅#9)。

$cron->binary('/home/myphp-cli'); // set PHP binary path, only if it's valid
$cron->binary('/home/myphp-cli',TRUE); // set PHP binary path, whether it's valid or not

silent

静默模式(默认=TRUE)

如果您想脚本输出已执行作业的列表,则禁用静默模式。

$cron->silent=FALSE;

set( $job, $handler, $expr )

安排作业

$cron->set('Job1','App->job1','@daily'); // runs daily
$cron->set('Job2','App->job2','*/5 * * * *'); // runs every 5 minutes
$cron->set('Job3','App->job3','0 8 * * 1'); // runs every Monday at 08:00

注意:作业名称的有效字符是字母数字字符和连字符。

preset( $name, $expr )

定义调度预设

$cron->preset('weekend','0 8 * * 6'); // runs every Saturday at 08:00
$cron->preset('lunch','0 12 * * *'); // runs every day at 12:00

注意:作业名称的有效字符是字母数字字符。

isDue( $job, $time )

如果请求的作业在给定时间应该执行,则返回TRUE

$cron->isDue('Job3',time()); // returns TRUE if Job3 is due now

execute( $job, $async=TRUE )

执行作业

$cron->execute('Job2',FALSE); // executes Job2 synchronously

run( $time=NULL, $async=TRUE )

运行调度程序,即执行给定时间应该执行的作业

$cron->run(strtotime('yesterday midnight'));
// run asynchronously all jobs due yesterday at midnight