nirmit / crunzplus
Crunz from Lavary - 更强大!直接在代码中安排任务。
Requires
- php: >=5.5
- guzzlehttp/guzzle: ^6.1
- jeremeamia/superclosure: ^2.2
- monolog/monolog: ^1.19
- mtdowling/cron-expression: ^1.1
- nesbot/carbon: ^1.21
- swiftmailer/swiftmailer: ^5.4
- symfony/config: ^3.0
- symfony/console: ^3.0
- symfony/finder: ^3.0
- symfony/process: ^3.0
- symfony/yaml: ^3.0
Requires (Dev)
- phpunit/phpunit: ^4.8 || ^5.0
This package is not auto-updated.
Last update: 2024-09-28 20:48:22 UTC
README
一次性安装cron作业,从代码中管理其余部分。
Crunz是一个框架无关的包,用于通过流畅的API在PHP中安排周期性任务(cron作业)。
Crunz能够执行任何类型的可执行命令以及PHP闭包。
安装
要安装它
composer require lavary/crunz
如果安装成功,将一个名为crunz
的命令行实用程序符号链接到您项目的vendor/bin
目录。
它是如何工作的?
想法非常简单:我们不是在crontab文件中安装cron作业,而是使用Crunz接口在单个或多个PHP文件中定义它们。
以下是一个基本示例
<?php // tasks/backupTasks.php use Crunz\Schedule; $schedule = new Schedule(); $schedule->run('cp project project-bk') ->daily(); return $schedule;
要运行任务,您只需要安装一个普通的cron作业(一个crontab条目),该作业每分钟运行一次,并将责任委托给Crunz的事件运行器
* * * * * /project/vendor/bin/crunz schedule:run
schedule:run
命令负责收集所有PHP任务文件并运行到期的任务。
任务文件
任务文件类似于crontab文件。就像crontab文件一样,它们可以包含一个或多个任务。
通常我们在项目的根目录中的tasks/
目录内创建我们的任务文件。
默认情况下,Crunz假设所有任务文件都位于项目根目录中的
tasks/
目录内。
有两种指定源目录的方法:1)配置文件 2)作为事件运行器命令的参数。
我们可以通过将参数传递给事件运行器来显式设置源路径
* * * * * /project/vendor/bin/crunz schedule:run /path/to/tasks/directory
创建一个简单的任务
在终端中,切换到您的项目根目录,并运行以下命令
mkdir tasks && cd tasks nano GeneralTasks.php
然后,添加以下任务
<?php // tasks/FirstTasks.php use Crunz\Schedule; $schedule = new Schedule(); $schedule->run('cp project project-bk') ->daily() ->description('Create a backup of the project directory.'); // ... // IMPORTANT: You must return the schedule object return $schedule;
创建任务文件有一些约定,您需要遵守。首先,文件名应以Tasks.php
结尾,除非我们通过配置设置更改此设置。
此外,我们必须在每个文件结束时返回Schedule
类的实例,否则事件运行器将跳过文件中的所有任务。
由于Crunz递归地扫描任务目录,我们可以将所有任务放在一个文件中,或者根据它们的用途放在不同的文件(或目录)中。这种行为有助于我们拥有一个井井有条的任务目录。
命令
我们可以使用run()
运行任何命令或脚本。此方法接受两个参数:要执行的命令和(如果有)命令选项(作为关联数组)。
普通命令或脚本
<?php use Crunz\Schedule; $schedule = new Schedule(); $schedule->run('/usr/bin/php backup.php', ['--destination' => 'path/to/destination']) ->everyMinute() ->description('Copying the project directory'); return $schedule;
在上面的示例中,--destination
是backup.php
脚本支持的一个选项。
闭包
我们也可以写一个闭包来代替命令
<?php use Crunz\Schedule; $schedule = new Schedule(); $x = 12; $schedule->run(function() use ($x) { // Do some cool stuff in here }) ->everyMinute() ->description('Copying the project directory'); return $schedule;
执行频率
有各种方法可以指定任务应该何时以及多久运行一次。我们可以将这些方法组合起来,以获得所需的时间间隔。
时间单位
有一组方法指定时间单位(大于分钟)作为频率。它们通常以ly
后缀结尾,如hourly()
、daily()
、weekly
、monthly()
、quarterly()
和yearly
。
<?php // ... $schedule->run('/usr/bin/php backup.php') ->daily(); // ...
上面的任务将在午夜每天运行一次。
这里还有一个,它是在每月的第一天运行的。
<?php // ... $schedule->run('/usr/bin/php email.php') ->monthly(); // ...
使用这一组方法安排的所有事件都发生在那个时间单位的开始。例如,
weekly()
将在周日运行事件,而monthly()
将在每月的第一天运行。
动态方法
动态方法可以在运行时提供广泛的频率选项。我们只需遵循以下模式
every[NumberInCamelCaseWords]Minute|Hour|Day|Months?
如我们所见,方法应以单词every
开头,后跟驼峰式命名的数字,以以下时间单位之一结尾:分钟、小时、天和月。
末尾的s
是可选的,只是为了语法。
话虽如此,以下方法是有效的
everyFiveMinutes()
everyMinute()
everyTwelveHours()
everyMonth
everySixMonths()
everyFifteenDays()
everyFiveHundredThirtySevenMinutes()
everyThreeThousandAndFiveHundredFiftyNineMinutes()
- ...
这是在任务文件中使用的方法
<?php // ... $schedule->run('/usr/bin/php email.php') ->everyTenDays(); $schedule->run('/usr/bin/php some_other_stuff.php') ->everyThirteenMinutes(); // ... return $schedule;
在特定时间运行事件
要安排一次性任务,可以使用on()
方法,如下所示
<?php // ... $schedule->run('/usr/bin/php email.php') ->on('13:30 2016-03-01'); // ...
上述任务将在2016年3月1日下午1:30运行。
On()
接受PHP的strtotime函数解析的任何日期格式。
要指定时间,我们使用at()
方法
<?php // ... $schedule->run('/usr/bin/php script.php') ->daily() ->at('13:30'); // ...
我们还可以使用dailyAt()
得到相同的结果
<?php // ... $schedule->run('/usr/bin/php script.php') ->dailyAt('13:30'); // ...
如果我们只向on()
方法传递时间,它将产生与使用at()
相同的效果
<?php // ... $schedule->run('/usr/bin/php email.php') ->mondays() ->on('13:30'); // is the sames as $schedule->run('/usr/bin/php email.php') ->mondays() ->at('13:30'); // ...
工作日
Crunz还提供了一套方法,用于指定一周中的某一天。这些方法被设计成用作约束,不应单独使用。原因是工作日方法仅修改cron作业表达式的“星期几”字段。
考虑以下示例
<?php // Cron equivalent: * * * * 1 $schedule->run('/usr/bin/php email.php') ->mondays();
乍一看,这个任务似乎在每个星期一运行,但由于它只修改了cron作业表达式的“星期几”字段,因此任务在每个星期一每分钟运行。
这是使用工作日方法的正确方式
<?php // ... $schedule->run('/usr/bin/php email.php') ->everyThreeHours() ->mondays(); // ...
在上面的任务中,我们使用mondays()
作为约束,以在星期一每三个小时运行任务。
设置单个字段
Crunz的方法不仅限于前面解释的现成方法。我们还可以设置单个字段以创建自定义频率。这些方法可以接受一个值数组,或者使用逗号分隔的列表参数
<?php // ... $schedule->run('/usr/bin/php email.php') ->minute(['1-30', 45, 55]) ->hour('1-5', 7, 8) ->dayOfMonth(12, 15) ->month(1);
或者
<?php // ... $schedule->run('/usr/bin/php email.php') ->minute('30') ->hour('13') ->month([1,2]) ->dayofWeek('Mon', 'Fri', 'Sat'); // ...
经典方法
我们也可以像在crontab文件中一样使用旧方法进行调度
<?php $schedule->run('/usr/bin/php email.php') ->cron('30 12 * 5-6,9 Mon,Fri');
根据我们的用例,我们可以选择和组合适当的工具集,这些工具集更容易使用。
更改目录
您可以使用in()
方法在运行命令之前更改目录
<?php // ... $schedule->run('./deploy.sh') ->in('/home') ->weekly() ->sundays() ->at('12:30') ->appendOutputTo('/var/log/backup.log'); // ... return $schedule;
任务生命周期
在crontab条目中,我们无法轻松地指定任务的寿命(任务活跃的时间段)。然而,在Crunz中,这已经变得简单了
<?php // $schedule->run('/usr/bin/php email.php') ->everyFiveMinutes() ->from('12:30 2016-03-04') ->to('04:55 2016-03-10'); //
或者我们可以使用between()
方法得到相同的结果
<?php // $schedule->run('/usr/bin/php email.php') ->everyFiveMinutes() ->between('12:30 2016-03-04', '04:55 2016-03-10'); //
如果我们不指定日期部分,任务将每天活跃,但仅限于指定的持续时间
<?php // $schedule->run('/usr/bin/php email.php') ->everyFiveMinutes() ->between('12:30', '04:55'); //
上述任务每天在下午12:30到下午4:55之间每五分钟运行。
运行条件
在传统的crontab文件中,我们无法轻松地为任务设置条件。但是,通过when()
和skip()
方法,这已经变得容易了。
考虑以下代码
<?php // $schedule->run('/usr/bin/php email.php') ->everyFiveMinutes() ->between('12:30 2016-03-04', '04:55 2016-03-10') ->when(function() { if ($some_condition_here) { return true; } }); //
方法 when()
接受一个回调函数,该回调函数必须返回 TRUE
才能执行任务。当我们需要在执行资源密集型任务之前检查资源时,这非常有用。
我们还可以使用 skip()
方法在某些条件下跳过任务。如果传入的回调函数返回 TRUE
,则任务将被跳过。
<?php
//
$schedule->run('/usr/bin/php email.php')
->everyFiveMinutes()
->between('12:30 2016-03-04', '04:55 2016-03-10')
->skip(function() {
if ($some_condition_here) { return true; }
});
//
对于单个任务,我们可以多次使用这些方法。它们按顺序进行评估。
配置
Crunz 以 YAML 格式提供了一些配置选项。为了修改配置设置,强烈建议保留配置文件的副本,而不是修改原始文件。
要创建配置文件的副本,首先我们需要发布配置文件
/project/vendor/bin/crunz publish:config The configuration file was generated successfully
因此,配置文件的副本将在我们的项目根目录中创建。
配置文件看起来像这样
# Crunz Configuration Settings # This option defines where the task files and # directories reside. # The path is relative to the project's root directory, # where the Crunz is installed (Trailing slashes will be ignored). source: tasks # The suffix is meant to target the task files inside the ":source" directory. # Please note if you change this value, you need # to make sure all the existing tasks files are renamed accordingly. suffix: Tasks.php # By default the errors are not logged by Crunz # You may set the value to true for logging the errors log_errors: false # This is the absolute path to the errors' log file # You need to make sure you have the required permission to write to this file though. errors_log_file: # By default the output is not logged as they are redirected to the # null output. # Set this to true if you want to keep the outputs log_output: false # This is the absolute path to the global output log file # The events which have dedicated log files (defined with them), won't be # logged to this file though. output_log_file: # This option determines whether the output should be emailed or not. email_output: false # This option determines whether the error messages should be emailed or not. email_errors: false # Global Swift Mailer settings # mailer: # Possible values: smtp, mail, and sendmail transport: smtp recipients: sender_name: sender_email: # SMTP settings # smtp: host: port: username: password: encryption:
如您所见,有几个选项,如 source
,用于指定源任务目录。其他选项用于错误/输出记录/电子邮件目的。
每次运行 Crunz 命令时,它都会查看项目的根目录,以查看是否存在任何用户修改的配置文件。如果配置文件不存在,它将使用随包一起提供的配置文件。
并行和锁定机制
Crunz 并行(在单独的进程)运行计划事件,因此具有相同执行频率的所有事件将异步同时运行。为了实现这一点,Crunz 使用 symfony/Process 库在子进程中运行任务。
如果一个任务的执行持续到下一个间隔甚至更长时间,我们称同一实例的任务是重叠的。在某些情况下,这不会成问题,但在某些情况下,这些任务正在修改数据库数据或文件,这可能会引起意外的行为,甚至数据丢失。
为了防止关键任务相互重叠,Crunz 通过 preventOverlapping()
方法提供锁定机制,该机制确保如果前一个实例正在运行,则不会运行任何任务。
<?php // $schedule->run('/usr/bin/php email.php') ->everyFiveMinutes() ->preventOverlapping(); //
保留输出
计划任务通常有输出,这些输出通常通过电子邮件发送给 crontab 文件的所有者,或者 crontab 文件内通过 MAILTO
环境变量设置的用户或用户组。
我们还可以使用 >
或 >>
运算符将标准输出重定向到物理文件
* * * * * /command/to/run >> /var/log/crons/cron.log
Crunz 已自动化了这类操作。要将每个事件的输出自动发送到日志文件,我们可以在配置文件中相应地设置 log_output
和 output_log_file
选项
# Configuration settings ## ... log_output: true output_log_file: /var/log/crunz.log ## ...
这会将事件的输出(如果执行成功)发送到 /var/log/crunz.log
文件。但是,我们需要确保我们有权限写入相应的文件。
如果我们需要按事件记录输出,我们可以像这样使用 appendOutputTo()
或 sendOutputTo()
方法
<?php // $schedule->run('/usr/bin/php email.php') ->everyFiveMinutes() ->appendOutputTo('/var/log/crunz/emails.log'); //
方法 appendOutputTo()
追加 输出到指定的文件。要每次运行后用新数据覆盖日志文件,我们使用 saveOutputTo()
方法。
还可以通过在配置文件中设置 email_output
和 mailer
设置,将错误作为电子邮件发送到一组收件人。
错误处理
Crunz 通过记录和允许添加一组错误回调来简化错误处理。
错误回调
您可以设置任意数量的回调,以便在发生错误时运行
<?php use Crunz\Schedule; $schedule = new Schedule(); $schedule->add('command/to/run') ->everyFiveMinutes(); $schedule ->onError(function(){ // Send mail }) ->onError(function(){ // Do something else }); return $schedule;
如果发生错误,将执行两个定义的回调。
错误记录
为了记录每次运行过程中可能出现的错误,我们可以在配置文件中设置log_error
和error_log_file
配置,如下所示
# Configuration settings # ... log_errors: true errors_log_file: /var/log/error.log # ...
因此,如果由于某些原因事件执行失败,错误信息将被追加到指定的错误日志文件中。每个条目都提供了有用的信息,包括发生时间、事件描述、导致错误的执行命令以及错误信息本身。
通过在配置文件中设置email_error
和mailer
配置,也可以将错误作为电子邮件发送给一组收件人。
预处理和后处理钩子
有时候,我们想在事件前后执行某些操作。通过将预处理和后处理回调附加到相应的事件上,这是可以实现的。
为此,我们在Event
和Schedule
对象上使用before()
和after()
,这意味着我们可以在事件级别以及调度级别上设置预和后钩子。与调度绑定的钩子将在所有事件之前运行,在所有事件完成后运行。
<?php // ... $schedule = new Schedule(); $schedule->run('/usr/bin/php email.php') ->everyFiveMinutes() ->before(function() { // Do something before the task runs }) ->before(function() { // Do something else }) ->after(function() { // After the task is run }); $schedule ->before(function () { // Do something before all events }) ->after(function () { // Do something after all events are finished } ->before(function () { // Do something before all events }); // ...
我们可能需要多次使用这些方法,可以通过链式调用它们。
只有当事件的执行成功时,才会调用后执行回调。
其他有用命令
我们已经使用了一些crunz
命令,如schedule:run
和publish:config
。
要查看crunz
的所有有效选项和参数,我们可以运行以下命令
vendor/bin/crunz --help
列出任务
其中这些命令之一是crunz schedule:list
,它以表格格式列出定义的任务(在收集的*.Tasks.php
文件中)。
vendor/bin/crunz schedule:list +---+---------------+-------------+--------------------+ | # | Task | Expression | Command to Run | +---+---------------+-------------+--------------------+ | 1 | Sample Task | * * * * 1 * | command/to/execute | +---+---------------+-------------+--------------------+
生成任务
还有一个名为make:task
的有用命令,它可以生成包含所有默认值的任务文件骨架,因此我们不必从头开始编写它们。我们可以根据我们的需求稍后修改输出文件。
例如,要创建一个每小时在星期一运行/var/www/script.php
的任务,我们运行以下命令
vendor/bin/crunz make:task exampleOne --run scripts.php --in /var/www --frequency everyHour --constraint mondays Where do you want to save the file? (Press enter for the current directory)
运行此命令时,Crunz会询问我们想要保存文件的路径。默认情况下,它是在我们的源任务目录。
因此,事件被定义在指定任务目录内的一个名为exampleOneTasks.php
的文件中。
要查看事件是否已成功创建,我们可以列出事件
crunz schedule:list +---+------------------+-------------+----------------+ | # | Task | Expression | Command to Run | +---+------------------+-------------+----------------+ | 1 | Task description | 0 * * * 1 * | scripts.php | +---+------------------+-------------+----------------+
要查看make:task
命令的所有选项及其默认值,我们可以运行此
vendor/bin/crunz make:task --help
如果您需要帮助
请使用GitHub问题提交所有问题和疑问,我将尽力帮助您。
许可证
Crunz是在MIT许可证条款下免费分发的软件。