这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
前言
定时任务在实际业务中经常用到,例如未支付订单超时取消,定时清理日志等。上一个项目是一个自动售货机,需要调用物联网设备,偶尔会有信号不好导致设备启动信号发出之后,接收不到设备启动信息,需要主动查询设备启动情况,启动成功将订单标记成功,失败的需要给用户退款。
初期是做了一个http接口,通过crontab定时调用触发,定期处理异常订单,但是当订单体量增大,任务执行时间增长,有时候会阻塞业务。后来改成了php命令行执行,满足了业务需求。
一、crontab
crontab 是用来让使用者在固定时间或固定间隔执行程序之用,也就是类似使用者的时程表。
定义格式如下:
minute hour day month week command
minute分钟,范围0-59。hour小时,范围0-23。day每月几号,范围1-31。month月份,范围1-12。week一周的第几天,范围0-7,0和7都是周日。command执行的命令。
当 minute 为 5 表示每五分钟执行一次 command;当值为 * 表示每个时间单位都执行一次;可以用, 隔开多个值,例如2,5,10 表示设定时间内的2分,5分,10分执行命令;可以用- 隔开两个值,例如10-20 设定时间内的第10分开始到20分结束每分钟执行一次命令;*/15表示每15分钟执行一次命令。其余单位设置方式相同。
举例:
-
每天上午10点-12点,每半个小时执行一次命令
*/30 10-12 * * * -
每年的5月1日和10月1日凌晨2点执行一次命令
0 2 1 5,10 *
二、ThinkPHP命令行指令
1. 创建项目
composer create-project topthink/think command-demo
cd command-demo 进入项目目录,接着执行 php think ,如果没有配置php环境变量可以使用绝对路径,例如/usr/local/php/bin/php think。如果打印出类似如下内容说明项目安装成功。
2. 创建自定义命令
php think make:command OrderCheckCommand ordercheck
上面命令的意思是在app/command/目录下 创建一个OrderCheckCommand.php php类文件,命令名称叫做ordercheck。
3. 注册指令
找到config/console.php 文件,添加如下代码:
<?php
return [
// 指令定义
'commands' => [
'ordercheck' => 'app\command\OrderCheckCommand'
],
];
试着执行命令 php think ordercheck 如果看到如下输出,则命令创建成功。
4. 指令说明
打开app/command/OrderCheckCommand.php
-
其中
configure方法是对指令的配置setName设置指令名称;setDescription设置指令描述内容;addArgument设置指令参数;addOption设置指令选项。 -
execute当执行命令时会执行execute中逻辑。
5. 编写业务指令
创建一个伪需求:指令接收一个订单状态参数,其中1是异常订单,需校验订单实际状态,2只查询失败订单,给用户退款;接收一个省份选项,如果输入省份则只处理某个省份的订单。
修改代码如下:
class OrderCheckCommand extends Command {
protected function configure() {
// 指令配置
$this->setName('ordercheck')
// Argument::OPTIONAL->可选参数 Argument::REQUIRED->必填参数 Argument::IS_ARRAY->数组参数
->addArgument('status', Argument::OPTIONAL, '订单状态', 1)
->addOption('province', 'p', Option::VALUE_REQUIRED, '订单所属省份', 'beijing')
->setDescription('the ordercheck command');
}
protected function execute(Input $input, Output $output) {
$status = intval($input->getArgument('status'));
$statusText = $status == 1 ? '订单状态为异常订单,进行订单实际状态校验' : '订单状态失败订单,退款给用户';
if ($input->hasOption('province')) {
$pre = '处理' . $input->getOption('province') . '订单;';
} else {
$pre = '处理全国订单;';
}
// 记录执行日志
Log::info($pre . $statusText);
// 指令输出
$output->writeln($pre . $statusText);
}
}
addArgument 接收四个参数,分别是名称、类型、描述、默认值;类型可选值分别为 Argument::OPTIONAL(可选参数)、Argument::REQUIRED(必填参数)、Argument::IS_ARRAY(数组参数)。
addOption 接收五个参数,分别是选项名称、别名(简写选项名)、类型、描述、默认值,其中类型可选值分别是Option::VALUE_NONE(无需传值)、Option::VALUE_REQUIRED(必须传值)、Option::VALUE_OPTIONAL(可选传值)、Option::VALUE_IS_ARRAY(传数组值)。
6. 测试指令
三、结合crontab部署定时任务
假设需要一个定时任务,每2分钟查询省份为beijing 的失败订单给用户退款,我们需要执行的命令就是:
php think ordercheck 2 -p beijing
当命令写到crontab中需要写项目的绝对路径,最终crontab写入内容如下:
*/2 * * * * php /home/www/command-demo/think ordercheck 2 -p beijing
首先执行crontab -e,添加上面内容,保存。
接着执行systemctl restart crond.service ,重启crontab。
等待几分钟之后查看日志,看命令是否执行。