xfra35 / f3-cron
PHP Fat-Free 框架的作业调度
Requires
- bcosca/fatfree-core: ~3.5
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模式访问,并旨在由服务器作业调度程序调用
- Unix cron或Windows任务计划程序每分钟(或更慢的速度)调用
index.php /cron
。 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/2
与1,3,5
相同*/3
与1,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 /cron
和GET 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 二进制文件是 php
或 php-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 插件每分钟实例化一次。每个实例都是独立运行的。
在一个实例中,可能有多个即将到来的作业,这些作业可以同步或异步运行。
如果您想在实例中异步运行即将到来的作业,您需要
- 在您的托管上启用
exec()
- 正确配置 脚本路径
- PHP CLI 二进制文件 可执行,并且位于您的托管用户路径中
注意:插件将自动检测作业是否可以异步运行。如果不能,作业将同步执行,这可能会花费更长的时间,并在作业失败的情况下增加队列丢失的风险。
常见错误
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