计划任务

使用说明

  1. 对于计划任务, 大部分时候我们依赖系统 通过CLI方式实现, 如: linux crontab
  2. 而一些情况下, 当需要动态生成异步并发操作时, 我们可以使用 "动态计划任务"
  3. 另一些情况下, 需要并发或失败重试操作时, 我们可以使用 "静态计划任务"
  4. 修复框架配置_of.com.timer.mode切换启动异步任务方式

动态计划任务 在代码执行时动态调用

of_base_com_timer::task($params, &$taskObj = null)

paramsarray
任务参数  {
    #动态任务, 未指定taskObj参数
    "time" : 执行时间, 五年内秒数=xx后秒执行, 其它=指定时间
    "call" : 框架标准的回调 接收 "自身" 数组做系统参数,可以修改其变量,如try,达到定时执行效果 
    "cNum" : 并发数量, 0=不设置, n=最大值, []=指定并发ID(最小值1)
    "try"  : 尝试相隔秒数, 默认[], 如:[60, 100, ...]

    #单子任务, taskObj返回任务对象
    "call" : 框架标准的回调

    #多子任务, taskObj返回 {任务标识 : 任务对象, ...}
    "list" : 任务列表 {任务标识 : 框架回调结构, ...}
    "cNum" : 最大并行任务数量
}
&taskObj
任务对象, 指定时为任务模式, swoole环境下性能更高
<?php
/**
 * 本函数内部会自动运行定时器, 如果定时器进程经常被系统杀死,
 * 可以在常用页面使用of_base_com_timer::timer()手动运行
 * _of.com.timer 为计划任务的配置
 * 如果 _of.com.timer.task.adapter 为 mysql, 需要下面的语句创建表, 也可以在 time 上做分区
 *      CREATE TABLE `_of_com_timer` (
 *          `hash` char(50) NOT NULL DEFAULT '' COMMENT '唯一标识符(十六进制时间戳+回调序列化的md5)',
 *          `time` int(11) NOT NULL DEFAULT '0' COMMENT '执行时间戳',
 *          `task` mediumtext NOT NULL COMMENT '存储调用数据{"call":回调结构,"try":尝试次数}',
 *          PRIMARY KEY (`hash`),
 *          KEY `根据时间查询执行范围` (`time`) USING BTREE
 *      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='框架计划任务存储列表';
 */
of_base_com_timer::task(array(
    'time' => 600,                                  //十分钟后触发回调
    'call' => array(
        'asCall' => 'demo_index::index',            //回调方法,返回 false 认为失败
        'params' => array('自定义参数1')            //自定义参数,
    ),
    'cNum' => 3,                                    //有且仅有3个并发一起执行
    'try'  => array(
        100,                                        //失败后100s重试
        90                                          //再失败90s重试
    )
));
<?php
/**
 * 获取回调任务返回信息
 */
of_base_com_timer::task(array(
    'call' => array(
        'asCall' => 'demo_index::index',            //回调方法,会回传返回值
        'params' => array('自定义参数1')            //自定义参数,
    ),
), $taskObj);

/**
 * 描述 : 获取任务结果
 * 参数 :
 *      wait : 最大尝试时间(秒), 默认86400(24小时), 0=尝试一次
 * 返回 :
 *      false=任务运行中, true=任务中途退出(exit throw kill), array=任务正常返回 {
 *          "result" : 任务返回的结果
 *      }
 */
var_dump($taskObj->result());
<?php
/**
 * 获取回调任务返回信息
 */
of_base_com_timer::task(array(
    'list' => array(
        'a' => array(
            'asCall' => 'demo_index::index',
            'params' => array('自定义参数1')
        ),
        'b' => array(
            'asCall' => 'demo_index::index',
            'params' => array('自定义参数1')
        )
    ),
    'cNum' => 1                                     //最大同时执行list中的一个任务
), $list);

print_r($list);                                     //{"a" : obj, "b" : obj}
echo time(), "\n";
foreach ($list as $k => &$v) {
    var_dump($v->result());
    echo time(), "\n";
}

静态计划任务 写在配置文件 "_of.com.timer.cron.path" 中指定的路径中

<?php
/**
 * OF_URL/index.php?c=of_base_com_timer 激活计划任务
 * call 与 try 参考 of_base_com_timer::task 动态计划任务
 * time 参数 符合 linux crontab 语法定义, "* * * * *" 分 时 日 月 星期(0-6 0为星期日)
 * "* * * * *" 每1分钟执行一次
 * "3,15 * * * *" 每小时的第3和第15分钟执行
 * "3,15 8-11 * * *" 上午8点到11点的第3和第15分钟执行
 * "3,15 8-11 */2 * *" 每隔两天的上午8点到11点的第3和第15分钟执行
 * "3,15 8-11 * * 1" 每个星期一的上午8点到11点的第3和第15分钟执行
 * "30 21 * * *" 每晚的21:30执行
 * "45 4 1,10,22 * *" 每月1、10、22日的4:45执行
 * "45 4 -1 * *" 负数为倒数, 每月最后一天的4:45执行
 * "0 2 * * 6,0" 每周六、周日的2:00执行
 * "* 2 * * 6,0" 每周六、周日的2:00-2:59每分钟执行一次
 * "0 20-7/2 * * *" 晚上8点到早上7点之间, 每隔2小时执行
 */
return array(
    array(                                                  //可以定义键值
        'time' => '*/2 */5,1,*,14-30/3 * * 1',              //符合 linux crontab 语法定义
        'call' => array(
            'asCall' => 'demo_ofControllers::cc',           //回调方法,返回 false 认为失败
            'params' => array('自定义参数1')                //自定义参数,
        ),
        'cNum' => 3,                                        //有且仅有3个并发一起执行
        'try'  => array(60, 120, 300)
    )
);

计划任务回调 动态与静态计划任务回调结构统一

call方法接收的触发参数结构
{
    "call" : 框架标准的回调,
    "time" : 执行时间, 时间戳,
    "cNum" : 并发数量, 0=不设置, n=最大并发
    "try"  : 尝试相隔秒数
    "this" : {
        "cMd5" :o回调唯一值, 并发时存在
        "cCid" :o并发ID, 从1开始, 并发时存在
        "mark" :o数据回传标识, 存在时标识回传, 子任务存在
        "type" : 任务类型, 1=定时器, 2=静态任务, 4=动态任务, 8=单子任务, 16=多子任务
    }
}

of_base_com_timer::data($data = true, $cIds = null, $call = null) 为并发提供共享数据

datanull bool array
读写数据, 仅可操作自身或未运行进程数据
    null=不读数据, 仅关注运行状态使用
    true=读取数据
    false=清空读取, 读取数据后清空原始数据
    数组=单层替换, 将数组键的值替换对应共享数据键的值
cIdsnull int bool array
指定任务中的并发ID
    null=读取自身
    数字=指定并发ID
    数组=多个并发ID, [并发ID, ...]
    true=正在运行
    false=包括停止
callnull string array
指定任务ID
    null=读取自身
    '/'开头字符串=指定任务ID
    符合框架回调结构=指定任务的回调
返回
{
    "info" : {
        并发ID, 从小到大排序 : {
            "isRun" : 是否运行, true=运行, false=停止
            "sort"  : 在返回列表中的位置, 从0开始
            "data"  : 并发所存修改前的数据
        }, ...
}
//在并发回调方法中调用
print_r(of_base_com_timer::data());                         //读取当前任务当前并发的存储数据
print_r(of_base_com_timer::data(null, true));               //读取当前任务运行并发的存储数据
print_r(of_base_com_timer::data(null, false));              //读取当前任务所有并发的存储数据

//假设通过 of_base_com_timer::info(1) 获取的任务ID为 $id
print_r(of_base_com_timer::data(null, true, '/' . $id));   //读取指定任务运行并发的存储数据

of_base_com_timer::info($type) 获取当期运行的信息

typeint
读取类型(可叠加), 1=并发的任务, 2=分布定时器, 4=当前任务
<?php
/**
 * type为1时 : 并发的任务 {
 *     任务ID : {
 *         "call" : 统一回调结构
 *         "list" : 运行的任务列表 {
 *             并发ID : {
 *                 "datetime"  : 任务启动时间
 *                 "timestamp" : 任务启动时间戳
 *             }
 *         }
 *     }
 * }
 * type为2时 : 分布定时器 {
 *     节点名称 : {}
 * }
 * type为4时 : 获取当前任务, null=当前不在异步中, array={
 *     "task" : 同task任务参数
 *     "cArg" : 并发参数, 数组=启动并发 {
 *          "cMd5" :o回调唯一值, 并发时存在
 *          "cCid" :o并发ID, 从1开始, 并发时存在
 *          "mark" :o数据回传标识, 存在时标识回传, 子任务存在
 *          "type" : 任务类型, 1=定时器, 2=静态任务, 4=动态任务, 8=单子任务, 16=多子任务
 *      }
 * }
 * type其它时 : 如1|2|4为7时 {
 *     "concurrent"  : type为1的结构,
 *     "taskTrigger" : type为2的结构,
 *     "nowTaskInfo" : type为4的结构
 * }
 */
print_r(of_base_com_timer::info(7));

/**
 * 输出如下 :
 * Array
 * (
 *     [concurrent] => Array
 *         (
 *             [305e58827000c31d7249a297790aa22f] => Array
 *                 (
 *                     [call] => Array
 *                         (
 *                             [0] => ctrl_index
 *                             [1] => asyn
 *                         )
 *                     [list] => Array
 *                         (
 *                             [1] => Array
 *                                 (
 *                                     [datetime] => 2023-12-11 17:19:00
 *                                     [timestamp] => 1702286340
 *                                 )
 *                         )
 *                 )
 *         )
 *     [taskTrigger] => Array
 *         (
 *             [da3c61c0c3bd31efcb4c17d5b2d754d5] => Array
 *                 (
 *                     [time] => 1702286078
 *                 )
 *         )
 *     [nowTaskInfo] => Array
 *         (
 *             [call] => Array
 *                 (
 *                     [time] => 1702286340
 *                     [call] => Array
 *                         (
 *                             [0] => ctrl_index
 *                             [1] => asyn
 *                         )
 *                     [cNum] => Array
 *                         (
 *                             [0] => 1
 *                         )
 *                     [try] => Array
 *                         (
 *                             [0] => 60
 *                             [1] => 120
 *                             [2] => 300
 *                         )
 *                 )
 *             [cArg] => Array
 *                 (
 *                     [cMd5] => 305e58827000c31d7249a297790aa22f
 *                     [cCid] => 1
 *                     [type] => 2
 *                 )
 *         )
 * )
 */

of_base_com_timer::renew($preg = true, $eTip = '') 判断已加载文件是否有更新

pregtrue string
忽略校验的正则, true=全校验, 字符串=以"@"开头的正则忽略路径
eTipstring
有更新时抛出错误, ""=不抛出, 字符串=抛出的错误信息
返回
true=有变动, false=未变动

二次开发

  1. 文件夹 /of/accy/com/timer 下存储着不同方式的异步任务对接文件
  2. 目前有已封装 default swoole
  3. 可以通过配置文件 _of.com.timer.fork.adapter 设置, 参考配置方式
  4. 开发更多的存储方式, 要实现以下方法

public static function fork($params) 启动异步任务

paramsarray
接收参数结构 {
    "asCall" : 回调方法,
    "params" : [
        自定义参数,
        {"type" : 任务类型(同计划任务回调结构中的"type"), ...}
    ]
}