ThinkPHP6自定义命令行指令结合crontab实现定时任务

2,100 阅读4分钟

这是我参与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 执行的命令。

minute5 表示每五分钟执行一次 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 如果看到如下输出,则命令创建成功。

image-20210807235956230

4. 指令说明

打开app/command/OrderCheckCommand.php

image-20210808000337925

  • 其中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. 测试指令

image-20210808004518523

三、结合crontab部署定时任务

假设需要一个定时任务,每2分钟查询省份为beijing 的失败订单给用户退款,我们需要执行的命令就是:

php think ordercheck 2 -p beijing

当命令写到crontab中需要写项目的绝对路径,最终crontab写入内容如下:

*/2 * * * * php /home/www/command-demo/think ordercheck 2 -p beijing

首先执行crontab -e,添加上面内容,保存。

image-20210808010826094

接着执行systemctl restart crond.service ,重启crontab。

image-20210808011007654

等待几分钟之后查看日志,看命令是否执行。

image-20210808011404367